ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2025-09-07 04:59:20
Exec Total Coverage
Lines: 198 5645 3.5%
Functions: 16 150 10.7%
Branches: 251 4389 5.7%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "base/zdefs.h"
8 #include "gui/editbox.h"
9 #include <iostream>
10 #include <sstream>
11 #include "base/zsys.h"
12 #include <stdio.h>
13 #include "base/util.h"
14 #include "pal.h"
15 #include "gui/tabpanel.h"
16 #include "gui/text_field.h"
17 #include "dialog/info.h"
18 #include "drawing.h"
19 using namespace util;
20 using std::string;
21 using std::istringstream;
22
23 void update_hw_screen();
24 extern int32_t zq_screen_w, zq_screen_h;
25 extern int32_t joystick_index;
26 int CheckerCol1 = 7, CheckerCol2 = 8;
27
28 int32_t abc_patternmatch = 1;
29
30 char abc_keypresses[1024] = {0};
31 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
32
33 /* these are provided for external use */
34 int32_t jwin_colors[jcMAX] =
35 {
36 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
37 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
38 };
39
40 int32_t scheme[jcMAX] =
41 {
42 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
43 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
44 };
45
46 int32_t jwin_pal[jcMAX] = {0};
47
48 // A pointer to this variable is used to identify the DIALOG belonging to
49 // the DialogRunner. It isn't used for anything else.
50 char newGuiMarker;
51
52 int32_t new_gui_event(DIALOG* d, guiEvent event)
53 {
54 for(int32_t i = 0; true; --d, ++i)
55 {
56 if(d->dp3 == &newGuiMarker)
57 {
58 d->d1 = i;
59 return d->proc(MSG_GUI_EVENT, d, event);
60 }
61 }
62
63 return -1;
64 }
65
66 void close_new_gui_dlg(DIALOG* d);
67
68 int32_t bound(int32_t x,int32_t low,int32_t high)
69 {
70 if(x<low) x=low;
71
72 if(x>high) x=high;
73
74 return x;
75 }
76 /*
77 float bound(float x,float low,float high)
78 {
79 if(x<low) x=low;
80 if(x>high) x=high;
81 return x;
82 }
83 */
84
85 int32_t get_selected_tab(TABPANEL* panel)
86 {
87 for(int32_t i=0; panel[i].text; ++i)
88 {
89 if((panel[i].flags&D_SELECTED)!=0)
90 return i;
91 }
92 return -1;
93 }
94
95 /* jwin_set_colors:
96 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
97 * into the current color scheme using the appropriate color depth
98 * conversions.
99 */
100 92 void jwin_set_colors(int32_t *colors)
101 {
102 92 int32_t i = 0;
103
104
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 if(bitmap_color_depth(screen) == 8)
105 {
106 // use color indices
107
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 1932 times.
2024 for(; i<jcMAX; i++)
108 1932 scheme[i] = colors[i];
109 92 }
110 else
111 {
112 // 0xRRGGBB format
113 for(; i<jcMAX; i++)
114 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
115 }
116 92 }
117
118 /* jwin_set_dialog_color:
119 * Sets the foreground and background colors of all the objects in a dialog.
120 *
121 * Needs work!
122 */
123 void jwin_set_dialog_color(DIALOG *dialog)
124 {
125 int32_t c;
126
127 for(c=0; dialog[c].proc; c++)
128 {
129 dialog[c].fg = scheme[jcMEDDARK];
130 dialog[c].bg = scheme[jcBOX];
131 }
132 }
133
134 /* jwin_draw_frame:
135 * Draws a frame using the specified style.
136 */
137 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
138 {
139 optional<int> c1,c2,c3,c4;
140
141 switch(style)
142 {
143 case FR_INVIS:
144 return;
145 case FR_BOX:
146 c1 = jcLIGHT;
147 c2 = jcMEDLT;
148 c3 = jcMEDDARK;
149 c4 = jcDARK;
150 break;
151
152 case FR_INV:
153 c1 = jcDARK;
154 c2 = jcMEDDARK;
155 c3 = jcMEDLT;
156 c4 = jcLIGHT;
157 break;
158
159 case FR_DEEP:
160 c1 = jcMEDDARK;
161 c2 = jcDARK;
162 c3 = jcMEDLT;
163 c4 = jcLIGHT;
164 break;
165
166 case FR_DARK:
167 c1 = jcDARK;
168 c2 = jcMEDDARK;
169 c3 = jcMEDDARK;
170 c4 = jcDARK;
171 break;
172
173 case FR_ETCHED:
174 c1 = jcMEDDARK;
175 c2 = jcLIGHT;
176 c3 = jcMEDDARK;
177 c4 = jcLIGHT;
178 break;
179
180 case FR_MEDDARK:
181 c1 = jcMEDDARK;
182 c2 = jcBOX;
183 c3 = jcBOX;
184 c4 = jcMEDDARK;
185 break;
186
187 case FR_MENU:
188 c1 = jcLIGHT;
189 c4 = jcMEDDARK;
190 break;
191 case FR_MENU_INV:
192 c1 = jcMEDDARK;
193 c2 = jcMEDDARK;
194 c3 = jcLIGHT;
195 c4 = jcLIGHT;
196 break;
197
198 case FR_WIN:
199 default:
200 c1 = jcMEDLT;
201 c2 = jcLIGHT;
202 c3 = jcMEDDARK;
203 c4 = jcDARK;
204 break;
205 }
206
207 if(c1) c1 = scheme[*c1];
208 if(c2) c2 = scheme[*c2];
209 if(c3) c3 = scheme[*c3];
210 if(c4) c4 = scheme[*c4];
211 switch (style)
212 {
213 case FR_RED:
214 c1 = 0xE4;
215 c2 = 0xEC;
216 c3 = 0xE4;
217 c4 = 0xEC;
218 break;
219 case FR_GREEN:
220 c1 = 0xE2;
221 c2 = 0xEA;
222 c3 = 0xE2;
223 c4 = 0xEA;
224 break;
225 }
226 if(c1)
227 {
228 hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
229 vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
230 }
231 if(c2)
232 {
233 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
234 vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
235 }
236 if(c3)
237 {
238 hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
239 vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
240 }
241 if(c4)
242 {
243
244 hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
245 vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
246 }
247 }
248 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
249 {
250 int c1,c2,c3,c4;
251
252 switch(style)
253 {
254 case FR_BOX:
255 c1 = jcLIGHT;
256 c2 = jcMEDLT;
257 c3 = jcMEDDARK;
258 c4 = jcDARK;
259 break;
260
261 case FR_INV:
262 c1 = jcDARK;
263 c2 = jcMEDDARK;
264 c3 = jcMEDLT;
265 c4 = jcLIGHT;
266 break;
267
268 case FR_DEEP:
269 c1 = jcMEDDARK;
270 c2 = jcDARK;
271 c3 = jcMEDLT;
272 c4 = jcLIGHT;
273 break;
274
275 case FR_DARK:
276 c1 = jcDARK;
277 c2 = jcMEDDARK;
278 c3 = jcMEDDARK;
279 c4 = jcDARK;
280 break;
281
282 case FR_ETCHED:
283 c1 = jcMEDDARK;
284 c2 = jcLIGHT;
285 c3 = jcMEDDARK;
286 c4 = jcLIGHT;
287 break;
288
289 case FR_MEDDARK:
290 c1 = jcMEDDARK;
291 c2 = jcBOX;
292 c3 = jcBOX;
293 c4 = jcMEDDARK;
294 break;
295
296 case FR_WIN:
297 default:
298 c1 = jcMEDLT;
299 c2 = jcLIGHT;
300 c3 = jcMEDDARK;
301 c4 = jcDARK;
302 break;
303 }
304
305 int xc = x1+fw-1;
306 int yc = y1+fh-1;
307 int x2 = x1+w-1;
308 int y2 = y1+h-1;
309
310 rectfill(dest, x1, y1, x2, yc, vc(0));
311 rectfill(dest, x1, yc, xc, y2, vc(0));
312
313 hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
314 hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
315
316 vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
317 vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
318
319 hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
320 hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
321
322 vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
323 vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
324
325 hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
326 hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
327
328 vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
329 vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
330 }
331 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
332 {
333 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
334 }
335
336 /* jwin_draw_win:
337 * Draws a window -- a box with a frame.
338 */
339 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
340 {
341 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
342 jwin_draw_frame(dest, x, y, w, h, frame);
343 }
344
345 /* jwin_draw_button:
346 * Helper function for buttons.
347 * Draws a box with a frame that depends on "state":
348 * 0: normal border (slightly different than window border)
349 * 1: inverted border
350 * 2: dark border
351 * 3: medium dark border
352 */
353 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
354 {
355 int32_t frame = FR_BOX;
356
357 if(type==1)
358 {
359 frame=FR_WIN;
360 }
361
362 switch(state)
363 {
364 case 1:
365 frame = FR_INV;
366 break;
367
368 case 2:
369 frame = FR_DARK;
370 break;
371
372 case 3:
373 frame = FR_MEDDARK;
374 break;
375 }
376
377 jwin_draw_win(dest, x, y, w, h, frame);
378 }
379
380 /* mix_value:
381 * Returns a mix of the values c1 and c2 with pos==0 being c1,
382 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
383 */
384 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
385 {
386 if(max<=0)
387 return c1;
388
389 return (c2 - c1) * pos / max + c1;
390 }
391
392 /* mix_color:
393 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
394 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
395 *
396 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
397 {
398 int32_t c;
399
400 if(bitmap_color_depth(screen) == 8)
401 c = mix_value(c1, c2, pos, max);
402 else
403 {
404 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
405 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
406 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
407 c = makecol(r,g,b);
408 }
409
410 return c;
411 }
412 */
413
414 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
415 {
416 strncpy(dest,src,maxchars);
417 dest[maxchars-1]='\0';
418 int32_t len=(int32_t)strlen(dest);
419 int32_t width=text_length(usefont, dest);
420 dest[len]=0;
421
422 while(width>maxwidth && len>4)
423 {
424 dest[len-4] = '.';
425 dest[len-3] = '.';
426 dest[len-2] = '.';
427 dest[len-1] = 0;
428 len--;
429 width=text_length(usefont, dest);
430 }
431
432 return dest;
433 }
434
435 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
436 {
437 char buf[512];
438 int32_t len = (int32_t)strlen(str);
439 int32_t length = text_length(font,str);
440 int32_t height = text_height(font);
441
442 int32_t tx = x + 2;
443 int32_t ty = y + (h-height)/2;
444 PALETTE temp_pal;
445 get_palette(temp_pal);
446 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
447 makecol15(temp_pal[scheme[jcTITLEL]].r,
448 temp_pal[scheme[jcTITLEL]].g,
449 temp_pal[scheme[jcTITLEL]].b),
450 makecol15(temp_pal[scheme[jcTITLER]].r,
451 temp_pal[scheme[jcTITLER]].g,
452 temp_pal[scheme[jcTITLER]].b),
453 scheme[jcTITLEL], scheme[jcTITLER]);
454
455
456 if(len>509)
457 len=509;
458
459 strncpy(buf,str,len);
460 buf[len]=0;
461
462 // this part needs work
463
464 if(length>w-20)
465 {
466 while(length>w-20 && len>1)
467 {
468 buf[len-4] = '.';
469 buf[len-3] = '.';
470 buf[len-2] = '.';
471 buf[len-1] = 0;
472 len--;
473 length = text_length(font,buf);
474 }
475 }
476
477 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
478
479 if(draw_button)
480 {
481 draw_x_button(dest, x + w - 18, y+2, 0);
482 }
483
484 if(helpbtn)
485 {
486 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
487 }
488
489 }
490
491 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
492 {
493 int32_t c = scheme[jcBOXFG];
494
495 jwin_draw_button(dest,x,y,16,14,state,0);
496 x += 4 + (state?1:0);
497 y += 3 + (state?1:0);
498
499 line(dest, x+2, y+0, x+5, y+0, c);
500 line(dest, x+1, y+1, x+2, y+1, c);
501 line(dest, x+5, y+1, x+6, y+1, c);
502 line(dest, x+4, y+2, x+5, y+2, c);
503 line(dest, x+3, y+3, x+4, y+3, c);
504 line(dest, x+3, y+4, x+4, y+4, c);
505 line(dest, x+3, y+6, x+4, y+6, c);
506 line(dest, x+3, y+7, x+4, y+7, c);
507 }
508
509 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
510 {
511 int32_t c = scheme[jcBOXFG];
512
513 jwin_draw_button(dest,x,y,16,14,state,0);
514 x += 4 + (state?1:0);
515 y += 3 + (state?1:0);
516
517 line(dest,x, y, x+6,y+6,c);
518 line(dest,x+1,y, x+7,y+6,c);
519 line(dest,x, y+6,x+6,y, c);
520 line(dest,x+1,y+6,x+7,y, c);
521 }
522
523 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
524 {
525 if(!center)
526 x += h-1;
527 for(int i = 0; i<h; i++)
528 hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
529 }
530 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
531 {
532 if(!center)
533 y += w-1;
534 for(int i = 0; i<w; i++)
535 vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
536 }
537 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
538 {
539 int32_t c = scheme[jcDARK];
540 int32_t ah = zc_min(h/3, 5);
541 int32_t i = 0;
542
543 jwin_draw_button(dest,x,y,w,h,state,1);
544 x += w/2 - (state?0:1);
545 y += (h-ah)/2 + (state?1:0);
546
547 for(; i<ah; i++)
548 {
549 hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
550 }
551 }
552
553 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
554 {
555 int32_t c = scheme[jcDARK];
556 int32_t aw = zc_min(w/3, 5);
557 int32_t i = 0;
558
559 jwin_draw_button(dest,x,y,w,h,state,1);
560 y += h/2 - (state?0:1);
561 x += (w-aw)/2 + (state?1:0);
562
563 for(; i<aw; i++)
564 {
565 vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
566 }
567 }
568
569 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
570 {
571 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
572 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
573 }
574
575 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
576 {
577 int32_t down=0, last_draw = 0;
578
579 while(gui_mouse_b())
580 {
581 down = mouse_in_rect(x,y,16,14);
582
583 if(down!=last_draw)
584 {
585 draw_x_button(dest,x,y,down);
586 last_draw = down;
587 }
588
589 /* let other objects continue to animate */
590 broadcast_dialog_message(MSG_IDLE, 0);
591 rest(1);
592 }
593
594 if(down)
595 {
596 draw_x_button(dest,x,y,0);
597 }
598
599 return down;
600 }
601
602 /* dotted_rect:
603 * Draws a dotted rectangle, for showing an object has the input focus.
604 */
605 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
606 {
607 int32_t x = ((x1+y1) & 1) ? 1 : 0;
608 int32_t c;
609
610 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
611 acquire_bitmap(dest);
612
613 for(c=x1; c<=x2; c++)
614 {
615 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
616 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
617 }
618
619 for(c=y1+1; c<y2; c++)
620 {
621 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
622 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
623 }
624
625 release_bitmap(dest);
626
627 }
628
629 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
630 {
631 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
632 }
633
634 static bool no_hline = false;
635 /* gui_textout_ln:
636 * Wrapper function for drawing text to the screen, which interprets the
637 * & character as an underbar for displaying keyboard shortcuts. Returns
638 * the width of the output string in pixels.
639 *
640 * Handles '\n' characters.
641 */
642 6 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
643 {
644 char tmp[1024];
645 6 int32_t c = 0;
646 int32_t len;
647 6 int32_t pix_len = 0;
648 6 int32_t max_len = 0;
649 int32_t hline_pos;
650 6 int32_t xx = x;
651 6 bool is_scr = bmp == screen;
652
653
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 6 times.
21 while(s[c])
654 {
655 15 len = 0;
656 15 hline_pos = -1;
657
658
4/4
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 798 times.
804 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
659 {
660
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[c] == '\n')
661 {
662 9 c++;
663 9 break;
664 }
665
2/4
✓ Branch 0 taken 789 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 789 times.
✗ Branch 3 not taken.
789 else if(!no_hline && s[c] == '&')
666 {
667 if(s[c+1] != '&')
668 hline_pos = len;
669 else
670 {
671 tmp[len++] = '&';
672 c++;
673 }
674 }
675 else
676 789 tmp[len++] = s[c];
677 789 }
678
679 15 tmp[len] = 0;
680 15 pix_len = text_length(f, tmp);
681
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (pix_len > max_len) max_len = pix_len;
682 15 x = xx;
683
684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(pos==1) //center
685 {
686 x -= pix_len / 2;
687 }
688
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 else if(pos==2) //right
689 {
690 x -= pix_len;
691 }
692
693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(bmp)
694 {
695 15 textout_ex(bmp, f, tmp, x, y, color,bg);
696
697
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if(hline_pos >= 0)
698 {
699 int32_t i;
700 i = tmp[hline_pos];
701 tmp[hline_pos] = 0;
702 hline_pos = text_length(f, tmp);
703 tmp[0] = i;
704 tmp[1] = 0;
705 i = text_length(f, tmp);
706 hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
707 }
708 15 }
709
710 15 y += text_height(f);
711 }
712 6 return max_len;
713 }
714
715 6 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
716 {
717 6 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
718 }
719
720 int32_t gui_text_width(FONT *f, const char *s)
721 {
722 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
723 }
724
725 6 int32_t count_newline(uint8_t *s)
726 {
727 6 int32_t cnt = 0;
728
2/2
✓ Branch 0 taken 798 times.
✓ Branch 1 taken 6 times.
804 for(int32_t q = 0; s[q] != 0; ++q)
729 {
730
2/2
✓ Branch 0 taken 789 times.
✓ Branch 1 taken 9 times.
798 if(s[q] == '\n') ++cnt;
731 798 }
732 6 return cnt;
733 }
734
735 6 int32_t gui_textheight(FONT* f, uint8_t *s)
736 {
737 6 return text_height(f) * (count_newline(s) + 1);
738 }
739
740 6 int32_t gui_textheight(uint8_t* s)
741 {
742 6 return gui_textheight(font, s);
743 }
744
745 /* typedef for the listbox callback functions */
746 typedef char *(*getfuncptr)(int32_t, int32_t *);
747
748 /* event handler that closes a dialog */
749 int32_t close_dlg()
750 {
751 return D_CLOSE;
752 }
753
754 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
755 {
756 //these are here to bypass compiler warnings about unused arguments
757 c=c;
758
759 if(msg == MSG_DRAW)
760 {
761 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
762 }
763
764 return D_O_K;
765 }
766
767 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
768 {
769 //these are here to bypass compiler warnings about unused arguments
770 c=c;
771
772 if(msg == MSG_DRAW)
773 {
774 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
775 }
776
777 return D_O_K;
778 }
779
780 /* jwin_win_proc:
781 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
782 * it won't draw a title bar. If the D_EXIT flag is set, it will also
783 * draw an "X" button on the title bar that can be used to close the
784 * dialog.
785 * If d->dp3 is non-null, it will be read as a help text string, and
786 * a ? button will be drawn, that upon clicking will display the helptext.
787 */
788 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
789 {
790 //these are here to bypass compiler warnings about unused arguments
791 c=c;
792
793 rest(1);
794 static bool skipredraw = false;
795
796 switch(msg)
797 {
798 case MSG_DRAW:
799 if(skipredraw)
800 {
801 skipredraw = false;
802 break;
803 }
804 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
805
806 if(d->dp)
807 {
808 FONT *oldfont = font;
809
810 if(d->dp2)
811 {
812 font = (FONT*)d->dp2;
813 }
814
815 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
816 font = oldfont;
817 }
818 break;
819
820 case MSG_WANTFOCUS:
821 if(gui_mouse_b())
822 return D_WANTFOCUS|D_REDRAW;
823 else return D_O_K;
824 case MSG_GOTFOCUS:
825 case MSG_LOSTFOCUS:
826 skipredraw = true;
827 return D_O_K;
828
829 case MSG_CLICK:
830 {
831 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
832 {
833 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
834 {
835 GUI_EVENT(d, geCLOSE);
836 return D_CLOSE;
837 }
838 }
839 if(char const* helpstr = (char const*)d->dp3)
840 {
841 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
842 {
843 broadcast_dialog_message(MSG_DRAW,0);
844 InfoDialog("Info", helpstr).show();
845 }
846 }
847 }
848 break;
849 }
850
851 return D_O_K;
852 }
853
854 /* jwin_text_proc:
855 * Simple dialog procedure: draws the text string which is pointed to by dp.
856 *
857 * Handles '\n' characters.
858 */
859 6 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
860 {
861 ASSERT(d);
862
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
863
864
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 switch(msg)
865 {
866 case MSG_START:
867 {
868 6 FONT *oldfont = font;
869
870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(d->dp2)
871 {
872 6 font = (FONT*)d->dp2;
873 6 }
874
875 6 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
876 6 d->h=gui_textheight((uint8_t *)d->dp);
877
878 6 font = oldfont;
879 6 break;
880 }
881 case MSG_DRAW:
882 {
883 FONT *oldfont = font;
884
885 if(d->dp2)
886 {
887 font = (FONT*)d->dp2;
888 }
889
890 if(d->flags & D_DISABLED)
891 {
892 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
893 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
894 }
895 else
896 {
897 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
898 }
899
900 font = oldfont;
901 break;
902 }
903 }
904
905 6 return D_O_K;
906 }
907
908 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
909 {
910 ASSERT(d);
911 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
912
913 switch(msg)
914 {
915 case MSG_START:
916 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
917 break;
918
919 case MSG_DRAW:
920 FONT *oldfont = font;
921
922 if(d->dp2)
923 {
924 font = (FONT*)d->dp2;
925 }
926
927 if(d->flags & D_DISABLED)
928 {
929 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
930 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
931 }
932 else
933 {
934 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
935 }
936
937 font = oldfont;
938 break;
939 }
940
941 return D_O_K;
942 }
943
944 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
945 {
946 ASSERT(d);
947 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
948
949 switch(msg)
950 {
951 case MSG_START:
952 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
953 break;
954
955 case MSG_DRAW:
956 FONT *oldfont = font;
957
958 if(d->dp2)
959 {
960 font = (FONT*)d->dp2;
961 }
962
963 if(d->flags & D_DISABLED)
964 {
965 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
966 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
967 }
968 else
969 {
970 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
971 }
972
973 font = oldfont;
974 break;
975 }
976
977 return D_O_K;
978 }
979
980 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
981 {
982 auto ret = d_ctext_proc(msg, d, c);
983 return ret;
984 }
985
986 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
987 {
988 BITMAP* oldscreen = screen;
989 if(msg==MSG_DRAW)
990 {
991 if(d->flags & D_HIDDEN) return D_O_K;
992 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
993 clear_bitmap(screen);
994 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
995 }
996 int32_t ret = D_O_K;
997 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
998 if(d->d2) no_hline = true;
999 switch(d->d1)
1000 {
1001 case 0:
1002 ret = jwin_text_proc(msg, d, c);
1003 break;
1004 case 1:
1005 d->x += d->w/2;
1006 ret = jwin_ctext_proc(msg, d, c);
1007 break;
1008 case 2:
1009 d->x += d->w - 1;
1010 ret = jwin_rtext_proc(msg, d, c);
1011 break;
1012 }
1013 no_hline = false;
1014 d->w = w;
1015 d->h = h;
1016 d->x = x;
1017 d->y = y;
1018 if(msg==MSG_DRAW)
1019 {
1020 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1021 destroy_bitmap(screen);
1022 screen = oldscreen;
1023 }
1024 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1025 ret |= D_WANTFOCUS|D_REDRAW;
1026 return ret;
1027 }
1028
1029 /* draw_text_button:
1030 * Helper for jwin_button_proc.
1031 */
1032 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1033 {
1034 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1035
1036 if(flags & D_SELECTED)
1037 {
1038 jwin_draw_button(dest, x, y, w, h, 2, 0);
1039 flags &= ~D_DISABLED;
1040 }
1041 else if(!(flags & D_GOTFOCUS))
1042 jwin_draw_button(dest, x, y, w, h, 0, 0);
1043 else
1044 {
1045 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1046 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1047 }
1048
1049 bool drawstring = true;
1050 if(str[1]==0 && byte(str[0]) >= 0x80)
1051 {
1052 drawstring = false;
1053 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1054 int aw = w/4, ah = h/4;
1055 int woff = (aw/2)+1, hoff = (ah/2)+1;
1056 int x1 = x+w/2, x2 = x+(w-aw)/2;
1057 int y1 = y+(h-aw)/2, y2 = y+h/2;
1058 switch(byte(str[0]))
1059 {
1060 case 0x88:
1061 draw_arrow(dest, col, x1, y1, ah, true, true);
1062 break;
1063 case 0x89:
1064 draw_arrow(dest, col, x1, y1, ah, false, true);
1065 break;
1066 case 0x8A:
1067 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1068 break;
1069 case 0x8B:
1070 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1071 break;
1072 case 0x98:
1073 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1074 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1075 break;
1076 case 0x99:
1077 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1078 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1079 break;
1080 case 0x9A:
1081 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1082 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1083 break;
1084 case 0x9B:
1085 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1086 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1087 break;
1088 default: drawstring = true;
1089 }
1090 }
1091 if(drawstring)
1092 {
1093 if(!(flags & D_DISABLED))
1094 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1095 else
1096 {
1097 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1098 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1099 }
1100 }
1101
1102 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1103 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1104 }
1105
1106 int icon_proportion(int icon,int s1,int s2)
1107 {
1108 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1109 switch(icon)
1110 {
1111 case BTNICON_STOPSQUARE:
1112 sz += 4;
1113 break;
1114 case BTNICON_PLUS:
1115 case BTNICON_MINUS:
1116 sz += 4;
1117 break;
1118 }
1119 return sz;
1120 }
1121 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1122 {
1123 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1124
1125 if(flags & D_SELECTED)
1126 jwin_draw_button(dest, x, y, w, h, 2, 0);
1127 else if(!(flags & D_GOTFOCUS))
1128 jwin_draw_button(dest, x, y, w, h, 0, 0);
1129 else
1130 {
1131 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1132 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1133 }
1134
1135 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1136 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1137
1138 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1139 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1140 }
1141 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1142 {
1143 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1144 }
1145 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1146 {
1147 int w2 = aw, h2 = ah;
1148 int sz = zc_min(aw,ah);
1149 switch(icon)
1150 {
1151 case BTNICON_ARROW_LEFT2:
1152 case BTNICON_ARROW_RIGHT2:
1153 aw *= 2;
1154 ah = aw*2-1;
1155 break;
1156 case BTNICON_ARROW_LEFT3:
1157 case BTNICON_ARROW_RIGHT3:
1158 aw *= 3;
1159 ah = aw*2-1;
1160 break;
1161 case BTNICON_ARROW_UP:
1162 case BTNICON_ARROW_DOWN:
1163 case BTNICON_CONTRACT_VERT:
1164 case BTNICON_EXPAND_VERT:
1165 aw = ah*2-1;
1166 break;
1167 case BTNICON_ARROW_LEFT:
1168 case BTNICON_ARROW_RIGHT:
1169 case BTNICON_CONTRACT_HORZ:
1170 case BTNICON_EXPAND_HORZ:
1171 ah = aw*2-1;
1172 break;
1173 case BTNICON_STOPSQUARE:
1174 aw = ah = sz;
1175 break;
1176 case BTNICON_PLUS:
1177 if(!(sz%2)) ++sz;
1178 aw = ah = w2 = h2 = sz;
1179 w2 /= 3;
1180 h2 /= 3;
1181 if(!(h2%2)) ++h2;
1182 if(!(w2%2)) ++w2;
1183 break;
1184 case BTNICON_MINUS:
1185 if(!(sz%2)) ++sz;
1186 aw = ah = w2 = h2 = sz;
1187 h2 /= 3;
1188 if(!(h2%2)) ++h2;
1189 break;
1190 }
1191 int woff = (aw/2)+1, hoff = (ah/2)+1;
1192 int cx = center ? (x-aw/2) : x,
1193 cy = center ? (y-ah/2) : y;
1194 switch(icon)
1195 {
1196 case BTNICON_ARROW_UP:
1197 draw_arrow(dest, col, x, cy, ah, true, center);
1198 break;
1199 case BTNICON_ARROW_DOWN:
1200 draw_arrow(dest, col, x, cy, ah, false, center);
1201 break;
1202 case BTNICON_ARROW_LEFT:
1203 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1204 break;
1205 case BTNICON_ARROW_RIGHT:
1206 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1207 break;
1208 case BTNICON_CONTRACT_VERT:
1209 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1210 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1211 break;
1212 case BTNICON_EXPAND_VERT:
1213 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1214 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1215 break;
1216 case BTNICON_CONTRACT_HORZ:
1217 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1218 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1219 break;
1220 case BTNICON_EXPAND_HORZ:
1221 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1222 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1223 break;
1224 case BTNICON_ARROW_LEFT2:
1225 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1226 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1227 break;
1228 case BTNICON_ARROW_LEFT3:
1229 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1230 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1231 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1232 break;
1233 case BTNICON_ARROW_RIGHT2:
1234 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1235 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1236 break;
1237 case BTNICON_ARROW_RIGHT3:
1238 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1239 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1240 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1241 break;
1242 case BTNICON_STOPSQUARE:
1243 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1244 break;
1245 case BTNICON_MINUS:
1246 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1247 break;
1248 case BTNICON_PLUS:
1249 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1250 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1251 break;
1252 }
1253 }
1254 /* draw_graphics_button:
1255 * Helper for jwin_button_proc.
1256 */
1257 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1258 {
1259 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1260
1261 if(flags & D_SELECTED)
1262 jwin_draw_button(dest, x, y, w, h, 2, 0);
1263 else if(!(flags & D_GOTFOCUS))
1264 jwin_draw_button(dest, x, y, w, h, 0, 0);
1265 else
1266 {
1267 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1268 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1269 }
1270
1271 if(!(flags & D_DISABLED))
1272 {
1273 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1274 if(bmp!=NULL)
1275 {
1276 if(overlay)
1277 {
1278 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1279 }
1280 else
1281 {
1282 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1283 }
1284 }
1285 }
1286 else
1287 {
1288 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1289 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1290 if(bmp2!=NULL)
1291 {
1292 if(overlay)
1293 {
1294 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1295 }
1296 else
1297 {
1298 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1299 }
1300 }
1301 }
1302
1303 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1304 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1305 }
1306
1307 /* jwin_button_proc:
1308 * A button object (the dp field points to the text string). This object
1309 * can be selected by clicking on it with the mouse or by pressing its
1310 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1311 * the dialog, otherwise it will toggle on and off.
1312 */
1313 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1314 {
1315 int32_t down=0;
1316 int32_t selected=(d->flags&D_SELECTED)?1:0;
1317 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1318 int32_t last_draw;
1319
1320 switch(msg)
1321 {
1322 case MSG_DRAW:
1323 {
1324 FONT *oldfont = font;
1325
1326 if(d->dp2)
1327 {
1328 font = (FONT*)d->dp2;
1329 }
1330
1331 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1332 font = oldfont;
1333 }
1334 break;
1335
1336 case MSG_WANTFOCUS:
1337 return D_WANTFOCUS;
1338
1339 case MSG_KEY:
1340 if(disabled) break;
1341 /* close dialog? */
1342 if(d->flags & D_EXIT)
1343 {
1344 return D_CLOSE;
1345 }
1346 if(d->d2 == 1) //Insta-button
1347 {
1348 GUI_EVENT(d, geCLICK);
1349 break;
1350 }
1351 /* or just toggle */
1352 d->flags ^= D_SELECTED;
1353 GUI_EVENT(d, geCLICK);
1354 object_message(d, MSG_DRAW, 0);
1355 break;
1356
1357 case MSG_CLICK:
1358 {
1359 if(disabled) break;
1360 if(d->d2 == 1) //Insta-button
1361 {
1362 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1363 {
1364 GUI_EVENT(d, geCLICK);
1365 if(d->flags & D_EXIT)
1366 return D_CLOSE;
1367 }
1368 }
1369 else
1370 {
1371 last_draw = 0;
1372
1373 /* track the mouse until it is released */
1374 while(gui_mouse_b())
1375 {
1376 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1377
1378 /* redraw? */
1379 bool should_redraw = false;
1380 if(last_draw != down)
1381 {
1382 if(down != selected)
1383 d->flags |= D_SELECTED;
1384 else
1385 d->flags &= ~D_SELECTED;
1386
1387 object_message(d, MSG_DRAW, 0);
1388 last_draw = down;
1389 should_redraw = true;
1390 }
1391
1392 /* let other objects continue to animate */
1393 int r = broadcast_dialog_message(MSG_IDLE, 0);
1394 if (r & D_REDRAWME) should_redraw = true;
1395
1396 if (should_redraw)
1397 {
1398 update_hw_screen();
1399 }
1400 }
1401
1402 /* redraw in normal state */
1403 if(down)
1404 {
1405 GUI_EVENT(d, geCLICK);
1406 if(d->flags&D_EXIT)
1407 {
1408 d->flags &= ~D_SELECTED;
1409 object_message(d, MSG_DRAW, 0);
1410 }
1411 }
1412
1413 /* should we close the dialog? */
1414 if(down && (d->flags & D_EXIT))
1415 return D_CLOSE;
1416 }
1417 }
1418 break;
1419 }
1420 return D_O_K;
1421 }
1422 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1423 {
1424 int32_t down=0;
1425 int32_t selected=(d->flags&D_SELECTED)?1:0;
1426 int32_t last_draw;
1427
1428 switch(msg)
1429 {
1430 case MSG_DRAW:
1431 {
1432 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1433 }
1434 break;
1435
1436 case MSG_WANTFOCUS:
1437 return D_WANTFOCUS;
1438
1439 case MSG_KEY:
1440 /* close dialog? */
1441 if(d->flags & D_EXIT)
1442 {
1443 return D_CLOSE;
1444 }
1445 if(d->d2 == 1) //Insta-button
1446 {
1447 GUI_EVENT(d, geCLICK);
1448 break;
1449 }
1450 /* or just toggle */
1451 d->flags ^= D_SELECTED;
1452 GUI_EVENT(d, geCLICK);
1453 object_message(d, MSG_DRAW, 0);
1454 break;
1455
1456 case MSG_CLICK:
1457 {
1458 if(d->d2 == 1) //Insta-button
1459 {
1460 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1461 {
1462 GUI_EVENT(d, geCLICK);
1463 if(d->flags & D_EXIT)
1464 return D_CLOSE;
1465 }
1466 }
1467 else
1468 {
1469 last_draw = 0;
1470
1471 /* track the mouse until it is released */
1472 while(gui_mouse_b())
1473 {
1474 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1475
1476 /* redraw? */
1477 bool should_redraw = false;
1478 if(last_draw != down)
1479 {
1480 if(down != selected)
1481 d->flags |= D_SELECTED;
1482 else
1483 d->flags &= ~D_SELECTED;
1484
1485 object_message(d, MSG_DRAW, 0);
1486 last_draw = down;
1487 should_redraw = true;
1488 }
1489
1490 /* let other objects continue to animate */
1491 int r = broadcast_dialog_message(MSG_IDLE, 0);
1492 if (r & D_REDRAWME) should_redraw = true;
1493
1494 if (should_redraw)
1495 {
1496 update_hw_screen();
1497 }
1498 }
1499
1500 /* redraw in normal state */
1501 if(down)
1502 {
1503 GUI_EVENT(d, geCLICK);
1504 if(d->flags&D_EXIT)
1505 {
1506 d->flags &= ~D_SELECTED;
1507 object_message(d, MSG_DRAW, 0);
1508 }
1509 }
1510
1511 /* should we close the dialog? */
1512 if(down && (d->flags & D_EXIT))
1513 return D_CLOSE;
1514 }
1515 }
1516 break;
1517 }
1518 return D_O_K;
1519 }
1520 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1521 {
1522 int32_t down=0;
1523 int32_t selected=(d->flags&D_SELECTED)?1:0;
1524 int32_t last_draw;
1525 std::string* str = (std::string*)d->dp;
1526 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1527 int flags = d->flags | (dis?D_DISABLED:0);
1528 bool show = false;
1529 switch(msg)
1530 {
1531 case MSG_DRAW:
1532 {
1533 FONT *oldfont = font;
1534
1535 if(d->dp2)
1536 font = (FONT*)d->dp2;
1537
1538 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1539 font = oldfont;
1540 }
1541 break;
1542
1543 case MSG_WANTFOCUS:
1544 if(dis) break;
1545 return D_WANTFOCUS;
1546
1547 case MSG_KEY:
1548 if(dis) break;
1549 show = true;
1550 break;
1551
1552 case MSG_CLICK:
1553 {
1554 if(dis) break;
1555 if(d->d2 == 1) //Insta-button
1556 {
1557 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1558 {
1559 show = true;
1560 break;
1561 }
1562 }
1563 else
1564 {
1565 last_draw = 0;
1566
1567 /* track the mouse until it is released */
1568 while(gui_mouse_b())
1569 {
1570 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1571
1572 /* redraw? */
1573 bool should_redraw = false;
1574 if(last_draw != down)
1575 {
1576 if(down != selected)
1577 d->flags |= D_SELECTED;
1578 else
1579 d->flags &= ~D_SELECTED;
1580
1581 object_message(d, MSG_DRAW, 0);
1582 last_draw = down;
1583 should_redraw = true;
1584 }
1585
1586 /* let other objects continue to animate */
1587 int r = broadcast_dialog_message(MSG_IDLE, 0);
1588 if (r & D_REDRAWME) should_redraw = true;
1589
1590 if (should_redraw)
1591 {
1592 update_hw_screen();
1593 }
1594 }
1595
1596 /* redraw in normal state */
1597 if(down)
1598 show = true;
1599 }
1600 }
1601 break;
1602 }
1603 if(show)
1604 {
1605 d->flags &= ~D_SELECTED;
1606 object_message(d, MSG_DRAW, 0);
1607 InfoDialog("Info",*str).show();
1608 GUI_EVENT(d, geCLICK);
1609 }
1610 return D_O_K;
1611 }
1612
1613 /* jwin_func_button_proc:
1614 * A button that runs a void() function when clicked.
1615 * dp: Button text
1616 * dp2: Function to run
1617 */
1618 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1619 {
1620 int32_t down=0;
1621 int32_t selected=(d->flags&D_SELECTED)?1:0;
1622 int32_t last_draw;
1623
1624 if(msg==MSG_CLICK || msg==MSG_KEY)
1625 {
1626 last_draw = 0;
1627
1628 /* track the mouse until it is released */
1629 while(gui_mouse_b())
1630 {
1631 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1632
1633 /* redraw? */
1634 bool should_redraw = false;
1635 if(last_draw != down)
1636 {
1637 if(down != selected)
1638 d->flags |= D_SELECTED;
1639 else
1640 d->flags &= ~D_SELECTED;
1641
1642 object_message(d, MSG_DRAW, 0);
1643 last_draw = down;
1644 should_redraw = true;
1645 }
1646
1647 /* let other objects continue to animate */
1648 int r = broadcast_dialog_message(MSG_IDLE, 0);
1649 if (r & D_REDRAWME) should_redraw = true;
1650
1651 if (should_redraw)
1652 {
1653 update_hw_screen();
1654 }
1655 }
1656
1657 /* redraw in normal state */
1658 if(down)
1659 {
1660 if(d->flags&D_EXIT)
1661 {
1662 d->flags &= ~D_SELECTED;
1663 object_message(d, MSG_DRAW, 0);
1664 }
1665 }
1666
1667 /* pop up and call the function */
1668 if(down)
1669 {
1670 d->flags &= ~D_SELECTED;
1671 object_message(d, MSG_DRAW, 0);
1672 typedef void (*funcType)(void);
1673 funcType func=reinterpret_cast<funcType>(d->dp3);
1674 func();
1675 }
1676
1677 return D_O_K;
1678 }
1679
1680 return jwin_button_proc(msg, d, c);
1681 }
1682
1683 /*(int32_t x = atoi(d->dp);
1684 if ( x > 256 )
1685 d->dp = (char*)"255";
1686 elseif (x < 0 ) d->dp = (char*)"0";
1687 */
1688
1689 #ifdef ALLEGRO_MACOSX
1690 static int WORD_FLAG = KB_ALT_FLAG;
1691 static int LINE_FLAG = KB_COMMAND_FLAG;
1692 #else
1693 static int WORD_FLAG = KB_CTRL_FLAG;
1694 static int LINE_FLAG = KB_ALT_FLAG;
1695 #endif
1696
1697 static int classify_char(char c)
1698 {
1699 if (c == ' ' || c == '\t' || c == '\r')
1700 return 0;
1701 if (c == '/')
1702 return 1;
1703 return 2;
1704 }
1705
1706 static void delete_word(char* s, int* cursor)
1707 {
1708 int start = *cursor;
1709 if (start == 0) return;
1710
1711 int i = start - 1;
1712 int first_ch_class = classify_char(s[i]);
1713 while (i >= 0 && s[i])
1714 {
1715 if (classify_char(s[i]) != first_ch_class)
1716 break;
1717 i--;
1718 }
1719
1720 i++;
1721 *cursor = i;
1722
1723 int j = start;
1724 while (s[j])
1725 s[i++] = s[j++];
1726 s[i] = 0;
1727 }
1728
1729 static void delete_line(char* s, int* cursor)
1730 {
1731 int start = *cursor;
1732 if (start == 0) return;
1733
1734 int i = start - 1;
1735 while (i >= 0 && s[i])
1736 {
1737 bool is_newline = s[i] == '\n';
1738 if (is_newline) break;
1739 i--;
1740 }
1741
1742 i++;
1743 *cursor = i;
1744
1745 int j = start;
1746 while (s[j])
1747 s[i++] = s[j++];
1748 s[i] = 0;
1749 }
1750
1751 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1752 {
1753 if(d->flags & D_HIDDEN)
1754 {
1755 switch(msg)
1756 {
1757 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1758 return D_O_K;
1759 }
1760 }
1761 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1762 return jwin_edit_proc(msg, d, c);
1763 static char nullbuf[2];
1764 sprintf(nullbuf, " ");
1765 int32_t f, l, p, w, x, y, fg, bg;
1766 int32_t lastSpace = -1;
1767 char *s;
1768 char buf[2] = {0,0};
1769
1770 if(d->dp==NULL)
1771 {
1772 d->dp=(void *)nullbuf;
1773 }
1774
1775 s = (char*)d->dp;
1776 l = (int32_t)strlen(s);
1777
1778 int32_t cursor_start = d->d2 & 0x0000FFFF;
1779 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1780 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1781 if (cursor_start == 0xFFFF)
1782 cursor_start = -1;
1783 if (cursor_end == 0xFFFF)
1784 cursor_end = -1;
1785
1786 if(cursor_start > l)
1787 cursor_start = l;
1788 if(cursor_end > l)
1789 cursor_end = l;
1790 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1791 auto high_cursor = zc_max(cursor_start,cursor_end);
1792 bool range_selected = cursor_end > -1;
1793
1794 FONT *oldfont = font;
1795 if(d->dp2)
1796 font = (FONT*)d->dp2;
1797
1798 auto* char_length = font->vtable->char_length;
1799 std::vector<size_t> lines;
1800 x = 0;
1801
1802 y = d->y + 2;
1803 size_t ind = 0;
1804 int32_t yinc = text_height(font)+2;
1805 int32_t maxy = y;
1806 size_t maxlines = 1;
1807 while(maxy+yinc < d->y+d->h-3)
1808 {
1809 maxy += yinc;
1810 ++maxlines;
1811 }
1812 size_t half_width = (maxlines-1)/2;
1813 size_t line_scroll = 0;
1814 size_t focused_line = size_t(-1);
1815 size_t focused_line2 = size_t(-1);
1816 switch(msg)
1817 {
1818 //Only these messages need these calculations, so save processing.
1819 case MSG_DRAW:
1820 case MSG_CLICK:
1821 case MSG_CHAR:
1822 {
1823 for(auto q = 0; q <= l; ++q)
1824 {
1825 char c = s[q] ? s[q] : ' ';
1826 x += char_length(font, c);
1827 if(x > d->w - 6)
1828 {
1829 // Line's too long, break
1830 if(lastSpace >= 0)
1831 {
1832 q = lastSpace+1;
1833 lines.push_back(q);
1834 lastSpace = -1;
1835 }
1836 else
1837 {
1838 lines.push_back(q);
1839 }
1840 x = 0;
1841 --q; //counteract increment
1842 }
1843 else if(c == ' ')
1844 lastSpace = q;
1845 }
1846 if(lines.empty() || lines.back() != l+1)
1847 lines.push_back(l+1);
1848 for(size_t line = 0; line < lines.size(); ++line)
1849 {
1850 if(size_t(range_selected ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1851 {
1852 focused_line = line;
1853 break;
1854 }
1855 }
1856 if(!range_selected)
1857 {
1858 focused_line2 = -1;
1859 }
1860 else for(size_t line = 0; line < lines.size(); ++line)
1861 {
1862 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1863 {
1864 focused_line2 = line;
1865 break;
1866 }
1867 }
1868 if (focused_line >= lines.size())
1869 focused_line = lines.size() - 1;
1870 if (focused_line2 >= lines.size())
1871 focused_line2 = lines.size() - 1;
1872 if(maxlines >= lines.size() || focused_line <= half_width)
1873 line_scroll = 0;
1874 else if(lines.size()-maxlines+half_width < focused_line)
1875 line_scroll = lines.size()-maxlines+half_width-1;
1876 else
1877 line_scroll = focused_line - half_width;
1878 }
1879 }
1880 font = oldfont; //in case of early return, need to reset here
1881 static bool dclick = false;
1882 switch(msg)
1883 {
1884 case MSG_START:
1885 dclick = false;
1886 cursor_start = (int32_t)strlen((char*)d->dp);
1887 cursor_end = -1;
1888 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1889 break;
1890
1891 case MSG_DRAW:
1892 {
1893 if(d->dp2)
1894 font = (FONT*)d->dp2;
1895 if(d->flags & D_DISABLED)
1896 {
1897 fg = scheme[jcDISABLED_FG];
1898 bg = scheme[jcDISABLED_BG];
1899 }
1900 else if(d->flags & D_READONLY)
1901 {
1902 fg = scheme[jcALT_TEXTFG];
1903 bg = scheme[jcALT_TEXTBG];
1904 }
1905 else
1906 {
1907 fg = scheme[jcTEXTFG];
1908 bg = scheme[jcTEXTBG];
1909 }
1910
1911 //Fill the BG
1912 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1913
1914 //Now the text
1915 size_t m = zc_min(line_scroll + maxlines, lines.size());
1916 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1917 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1918 {
1919 x = 3;
1920 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1921 {
1922 char c = s[ind] ? s[ind] : ' ';
1923 w = char_length(font, c);
1924 bool focused = range_selected
1925 ? (ind >= low_cursor && ind <= high_cursor)
1926 : (ind == cursor_start);
1927 f = (focused && (d->flags & D_GOTFOCUS));
1928 buf[0] = c;
1929 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1930 x += w;
1931 }
1932 }
1933
1934 font = oldfont;
1935 break;
1936 }
1937
1938 case MSG_DCLICK:
1939 if ((gui_mouse_b() & 2) != 0)
1940 break;
1941 if (d->flags & (D_DISABLED | D_READONLY))
1942 break;
1943 dclick = true;
1944 break;
1945 case MSG_CLICK:
1946 {
1947 if(d->flags & (D_DISABLED|D_READONLY))
1948 break;
1949 if(d->dp2)
1950 font = (FONT*)d->dp2;
1951
1952 bool found = false;
1953 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1954 {
1955 if(gui_mouse_y() >= y+yinc)
1956 continue;
1957 x = d->x+3;
1958 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1959 {
1960 x += char_length(font, s[ind]);
1961 if(x >= gui_mouse_x())
1962 {
1963 if(key_shifts&KB_SHIFT_FLAG)
1964 cursor_end = ind;
1965 else
1966 {
1967 cursor_start = ind;
1968 cursor_end = -1;
1969 if (dclick)
1970 cursor_end = cursor_start;
1971 }
1972 found = true;
1973 break;
1974 }
1975 }
1976 break;
1977 }
1978 if(!found)
1979 {
1980 if(key_shifts&KB_SHIFT_FLAG)
1981 cursor_end = l;
1982 else
1983 {
1984 cursor_start = l;
1985 cursor_end = -1;
1986 if (dclick)
1987 cursor_end = cursor_start;
1988 }
1989 }
1990
1991 if (dclick)
1992 {
1993 while (cursor_start > 0 && cursor_start < l)
1994 {
1995 if (s[cursor_start] == ' ')
1996 {
1997 if (cursor_start <= cursor_end)
1998 ++cursor_start;
1999 else
2000 --cursor_start;
2001 break;
2002 }
2003 if (cursor_start <= cursor_end)
2004 --cursor_start;
2005 else
2006 ++cursor_start;
2007 }
2008 while (cursor_end > 0 && cursor_end < l)
2009 {
2010 if (s[cursor_end] == ' ')
2011 {
2012 if (cursor_end >= cursor_start)
2013 --cursor_end;
2014 else
2015 ++cursor_end;
2016 break;
2017 }
2018 if (cursor_end >= cursor_start)
2019 ++cursor_end;
2020 else
2021 --cursor_end;
2022 }
2023 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2024 d->flags |= D_DIRTY;
2025 }
2026 else
2027 {
2028 if (cursor_end == cursor_start) cursor_end = -1;
2029 else d->flags |= D_DIRTY;
2030 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2031 }
2032
2033 object_message(d, MSG_DRAW, 0);
2034 font = oldfont;
2035 dclick = false;
2036 break;
2037 }
2038
2039 case MSG_WANTFOCUS:
2040 case MSG_LOSTFOCUS:
2041 case MSG_KEY:
2042 if(d->flags & (D_DISABLED|D_READONLY))
2043 break;
2044 return D_WANTFOCUS;
2045
2046 case MSG_CHAR:
2047 {
2048 if(d->flags & (D_DISABLED|D_READONLY))
2049 break;
2050 bool shifted = key_shifts & KB_SHIFT_FLAG;
2051 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2052 bool word_modifier = key_shifts & WORD_FLAG;
2053 bool line_modifier = key_shifts & LINE_FLAG;
2054 bool change_cursor = true;
2055 int32_t scursor = cursor_start, ecursor = cursor_end;
2056 char upper_c = c>>8;
2057 char lower_c = c&255;
2058
2059 if(shifted)
2060 {
2061 if(ecursor < 0)
2062 {
2063 ecursor = scursor;
2064 focused_line2 = focused_line;
2065 }
2066 }
2067 if(upper_c == KEY_LEFT)
2068 {
2069 if(shifted)
2070 {
2071 if(ecursor>0)
2072 --ecursor;
2073 }
2074 else
2075 {
2076 ecursor = -1;
2077 if(scursor > 0)
2078 --scursor;
2079 }
2080 }
2081 else if(upper_c == KEY_RIGHT)
2082 {
2083 if(shifted)
2084 {
2085 if(ecursor < l)
2086 ++ecursor;
2087 }
2088 else
2089 {
2090 ecursor = -1;
2091 if(scursor < l)
2092 ++scursor;
2093 }
2094 }
2095 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2096 {
2097 if(shifted)
2098 {
2099 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2100 if(!focused_line2 && upper_c == KEY_UP)
2101 ecursor = 0;
2102 else if(line >= lines.size())
2103 ecursor = l;
2104 else
2105 {
2106 if(d->dp2)
2107 font = (FONT*)d->dp2;
2108 x = d->x + 3;
2109 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2110 {
2111 w = char_length(font, s[ind]);
2112 if(ind < size_t(ecursor))
2113 x += w;
2114 else
2115 {
2116 x += w / 2;
2117 break;
2118 }
2119 }
2120
2121 int32_t tx = d->x+3;
2122 bool done = false;
2123 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2124 {
2125 tx += char_length(font, s[ind] ? s[ind] : ' ');
2126 if(tx < x)
2127 continue;
2128 ecursor = ind;
2129 done = true;
2130 break;
2131 }
2132 font = oldfont;
2133 if(!done)
2134 {
2135 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2136 }
2137 }
2138 }
2139 else
2140 {
2141 ecursor = -1;
2142 if(range_selected)
2143 {
2144 focused_line = focused_line2;
2145 scursor = ecursor;
2146 }
2147 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2148 if(!focused_line && upper_c == KEY_UP)
2149 scursor = 0;
2150 else if(line >= lines.size())
2151 scursor = l;
2152 else
2153 {
2154 if(d->dp2)
2155 font = (FONT*)d->dp2;
2156 x = d->x + 3;
2157 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2158 {
2159 w = char_length(font, s[ind]);
2160 if(ind < size_t(scursor))
2161 x += w;
2162 else
2163 {
2164 x += w / 2;
2165 break;
2166 }
2167 }
2168
2169 int32_t tx = d->x+3;
2170 bool done = false;
2171 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2172 {
2173 tx += char_length(font, s[ind] ? s[ind] : ' ');
2174 if(tx < x)
2175 continue;
2176 scursor = ind;
2177 done = true;
2178 break;
2179 }
2180 font = oldfont;
2181 if(!done)
2182 {
2183 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2184 }
2185 }
2186 }
2187 }
2188 else if(upper_c == KEY_HOME)
2189 {
2190 if(shifted)
2191 ecursor = 0;
2192 else
2193 {
2194 ecursor = -1;
2195 scursor = 0;
2196 }
2197 }
2198 else if(upper_c == KEY_END)
2199 {
2200 if(shifted)
2201 ecursor = l;
2202 else
2203 {
2204 ecursor = -1;
2205 scursor = l;
2206 }
2207 }
2208 else if(upper_c == KEY_DEL)
2209 {
2210 if(ctrl)
2211 {
2212 s[0] = 0;
2213 scursor = 0;
2214 ecursor = -1;
2215 GUI_EVENT(d, geCHANGE_VALUE);
2216 }
2217 else if(range_selected)
2218 {
2219 ecursor = -1;
2220 scursor = low_cursor;
2221 size_t ind = low_cursor, ind2 = high_cursor+1;
2222 while(ind2 < l && s[ind2])
2223 s[ind++] = s[ind2++];
2224 while(s[ind])
2225 s[ind++] = 0;
2226 GUI_EVENT(d, geCHANGE_VALUE);
2227 }
2228 else if(scursor < l)
2229 {
2230 for(p=scursor; s[p]; p++)
2231 s[p] = s[p+1];
2232 GUI_EVENT(d, geCHANGE_VALUE);
2233 }
2234 }
2235 else if(upper_c == KEY_BACKSPACE)
2236 {
2237 if(line_modifier)
2238 {
2239 delete_line(s, &scursor);
2240 ecursor = -1;
2241 GUI_EVENT(d, geCHANGE_VALUE);
2242 }
2243 else if(word_modifier)
2244 {
2245 delete_word(s, &scursor);
2246 ecursor = -1;
2247 GUI_EVENT(d, geCHANGE_VALUE);
2248 }
2249 else if(range_selected)
2250 {
2251 ecursor = -1;
2252 scursor = low_cursor;
2253 size_t ind = low_cursor, ind2 = high_cursor+1;
2254 while(ind2 < l && s[ind2])
2255 s[ind++] = s[ind2++];
2256 while(s[ind])
2257 s[ind++] = 0;
2258 GUI_EVENT(d, geCHANGE_VALUE);
2259 }
2260 else if(scursor > 0)
2261 {
2262 --scursor;
2263 for(p=scursor; s[p]; p++)
2264 s[p] = s[p+1];
2265 GUI_EVENT(d, geCHANGE_VALUE);
2266 }
2267 }
2268 else if(upper_c == KEY_ENTER)
2269 {
2270 change_cursor = false;
2271 GUI_EVENT(d, geENTER);
2272 if(d->flags & D_EXIT)
2273 {
2274 object_message(d, MSG_DRAW, 0);
2275 return D_CLOSE;
2276 }
2277 else
2278 return D_O_K;
2279 }
2280 else if(upper_c == KEY_TAB)
2281 {
2282 change_cursor = false;
2283 return D_O_K;
2284 }
2285 else if(ctrl && upper_c == KEY_C)
2286 {
2287 change_cursor = false;
2288 std::ostringstream oss;
2289 if(range_selected)
2290 {
2291 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2292 {
2293 if(s[ind])
2294 oss << s[ind];
2295 }
2296 }
2297 else
2298 {
2299 if(s[scursor])
2300 oss << s[scursor];
2301 }
2302 set_al_clipboard(oss.str());
2303 }
2304 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2305 {
2306 std::string cb;
2307 if(get_al_clipboard(cb))
2308 {
2309 int ind = low_cursor, ind2 = high_cursor + 1;
2310 if (range_selected)
2311 {
2312 //Delete selected text
2313 ecursor = -1;
2314 scursor = low_cursor;
2315 while (s[ind2] && ind2 < l)
2316 s[ind++] = s[ind2++];
2317 while (s[ind])
2318 s[ind++] = 0;
2319 l = (int32_t)strlen(s);
2320 }
2321 //Move the text out of the way of the pasting
2322 int paste_len = cb.size();
2323 int paste_start = scursor;
2324 int paste_end = paste_start+paste_len;
2325 ind = strlen(s);
2326 ind2 = ind+paste_len;
2327 while(ind2 > d->d1)
2328 {
2329 --ind;
2330 --ind2;
2331 }
2332 size_t new_l = ind2;
2333 while(ind >= paste_start)
2334 {
2335 if(s[ind] || (ind&&s[ind-1]))
2336 {
2337 s[ind2] = s[ind];
2338 }
2339 --ind2; --ind;
2340 }
2341 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2342 {
2343 s[paste_start+q] = cb.at(q);
2344 }
2345 s[new_l] = 0;
2346 scursor = paste_start + paste_len;
2347 ecursor = -1;
2348 GUI_EVENT(d, geCHANGE_VALUE);
2349 }
2350 }
2351 else if (ctrl && upper_c == KEY_A)
2352 {
2353 cursor_start = 0;
2354 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2355 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2356 d->flags |= D_DIRTY;
2357 break;
2358 }
2359 else if(lower_c >= 32 && !ctrl)
2360 {
2361 if(range_selected)
2362 {
2363 //Delete selected text
2364 ecursor = -1;
2365 scursor = low_cursor;
2366 size_t ind = low_cursor, ind2 = high_cursor+1;
2367 while(ind2 < l && s[ind2])
2368 s[ind++] = s[ind2++];
2369 while(s[ind])
2370 s[ind++] = 0;
2371 l = (int32_t)strlen(s);
2372 //Type the character in its' place
2373 //(fallthrough)
2374 }
2375 if(l < d->d1)
2376 {
2377 ecursor = -1;
2378 s[l+1] = 0;
2379 size_t ind = l;
2380 while(ind >= scursor)
2381 {
2382 s[ind+1] = s[ind];
2383 if (!ind) break;
2384 --ind;
2385 }
2386
2387 s[scursor++] = lower_c;
2388
2389 GUI_EVENT(d, geCHANGE_VALUE);
2390 }
2391 }
2392 else
2393 return D_O_K;
2394
2395 if(change_cursor)
2396 {
2397 if (cursor_start != scursor)
2398 d->flags |= D_DIRTY;
2399
2400 cursor_end = ecursor; cursor_start = scursor;
2401 if (cursor_end == cursor_start) cursor_end = -1;
2402 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2403 }
2404
2405 /* if we changed something, better redraw... */
2406 object_message(d, MSG_DRAW, 0);
2407 return D_USED_CHAR;
2408 }
2409 }
2410
2411 return D_O_K;
2412 }
2413
2414 /* jwin_edit_proc:
2415 * An editable text object (the dp field points to the string). When it
2416 * has the input focus (obtained by clicking on it with the mouse), text
2417 * can be typed into this object. The d1 field specifies the maximum
2418 * number of characters that it will accept, and d2 is the text cursor
2419 * position within the string.
2420 */
2421 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2422 {
2423 if(d->flags & D_HIDDEN)
2424 {
2425 switch(msg)
2426 {
2427 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2428 return D_O_K;
2429 }
2430 }
2431 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2432 return jwin_vedit_proc(msg, d, c);
2433 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2434 int32_t b;
2435 int32_t scroll;
2436 char *s;
2437 char buf[2];
2438 static char nullbuf[2];
2439 sprintf(nullbuf, " ");
2440
2441 if(d->dp==NULL)
2442 {
2443 d->dp=(void *)nullbuf;
2444 }
2445
2446 s = (char*)d->dp;
2447 l = (int32_t)strlen(s);
2448
2449 int32_t cursor_start = d->d2 & 0x0000FFFF;
2450 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2451 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2452 if (cursor_start == 0xFFFF)
2453 cursor_start = -1;
2454 if (cursor_end == 0xFFFF)
2455 cursor_end = -1;
2456
2457 if(cursor_start > l)
2458 cursor_start = l;
2459 if(cursor_end > l)
2460 cursor_end = l;
2461 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2462 auto high_cursor = zc_max(cursor_start,cursor_end);
2463
2464 /* calculate maximal number of displayable characters */
2465 b = x = 0;
2466
2467 if(cursor_start == l)
2468 {
2469 buf[0] = ' ';
2470 buf[1] = 0;
2471
2472 if(d->dp2)
2473 x = text_length((FONT*)d->dp2, buf);
2474 else
2475 x = text_length(font, buf);
2476 }
2477
2478 buf[1] = 0;
2479
2480 for(p=cursor_start; p>=0; p--)
2481 {
2482 buf[0] = s[p];
2483 b++;
2484
2485 if(d->dp2)
2486 x += text_length((FONT*)d->dp2, buf);
2487 else
2488 x += text_length(font, buf);
2489
2490 if(x > d->w-6)
2491 break;
2492 }
2493
2494 if(x <= d->w-6)
2495 {
2496 b = l;
2497 scroll = FALSE;
2498 }
2499 else
2500 {
2501 b--;
2502 scroll = TRUE;
2503 }
2504
2505 FONT *oldfont = font;
2506 static bool dclick = false;
2507 switch(msg)
2508 {
2509 case MSG_START:
2510 dclick = false;
2511 cursor_start = (int32_t)strlen((char*)d->dp);
2512 cursor_end = -1;
2513 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2514 break;
2515
2516 case MSG_DRAW:
2517 {
2518 if(d->dp2)
2519 {
2520 font = (FONT*)d->dp2;
2521 }
2522 if(d->flags & D_DISABLED)
2523 {
2524 fg2 = scheme[jcLIGHT];
2525 bg2 = scheme[jcDISABLED_BG];
2526 fg = scheme[jcDISABLED_FG];
2527 bg = -1;
2528 fg3 = fg;
2529 bg3 = bg2;
2530 }
2531 else if(d->flags & D_READONLY)
2532 {
2533 fg = scheme[jcALT_TEXTFG];
2534 bg = scheme[jcALT_TEXTBG];
2535 fg3 = fg;
2536 bg3 = bg;
2537 }
2538 else
2539 {
2540 fg = scheme[jcTEXTFG];
2541 bg = scheme[jcTEXTBG];
2542 fg3 = fg;
2543 bg3 = bg;
2544 }
2545
2546 x = 3;
2547 y = (d->h - text_height(font)) / 2 + d->y;
2548
2549 /* first fill in the edges */
2550
2551 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2552
2553 vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2554
2555 /* now the text */
2556
2557 if(scroll)
2558 {
2559 p = cursor_start-b+1;
2560 b = cursor_start;
2561 }
2562 else
2563 p = 0;
2564 for(; p<=b; p++)
2565 {
2566 buf[0] = s[p] ? s[p] : ' ';
2567 w = text_length(font, buf);
2568
2569 if(x+w > d->w)
2570 break;
2571 bool focused = (cursor_end>-1)
2572 ? (p >= low_cursor && p <= high_cursor)
2573 : (p == cursor_start);
2574 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2575 if(fg2 > -1)
2576 {
2577 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2578 }
2579 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2580 x += w;
2581 }
2582
2583 if(x < d->w-2)
2584 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2585
2586 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2587 font = oldfont;
2588 break;
2589 }
2590
2591 case MSG_DCLICK:
2592 if ((gui_mouse_b() & 2) != 0)
2593 break;
2594 if (d->flags & (D_DISABLED | D_READONLY))
2595 break;
2596 dclick = true;
2597 break;
2598 case MSG_CLICK:
2599 {
2600 if(d->flags & (D_DISABLED|D_READONLY))
2601 break;
2602 x = d->x+3;
2603
2604 if(scroll)
2605 {
2606 p = cursor_start-b+1;
2607 b = cursor_start;
2608 }
2609 else
2610 p = 0;
2611
2612 for(; p<b; p++)
2613 {
2614 buf[0] = s[p];
2615 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2616
2617 if(x > gui_mouse_x())
2618 break;
2619 }
2620
2621 if(key_shifts&KB_SHIFT_FLAG)
2622 cursor_end = MID(0, p, l);
2623 else
2624 {
2625 cursor_end = -1;
2626 cursor_start = MID(0, p, l);
2627 if (dclick)
2628 cursor_end = cursor_start;
2629 }
2630
2631 if (dclick)
2632 {
2633 while (cursor_start > 0 && cursor_start < l)
2634 {
2635 if (s[cursor_start] == ' ')
2636 {
2637 if (cursor_start <= cursor_end)
2638 ++cursor_start;
2639 else
2640 --cursor_start;
2641 break;
2642 }
2643 if (cursor_start <= cursor_end)
2644 --cursor_start;
2645 else
2646 ++cursor_start;
2647 }
2648 while (cursor_end > 0 && cursor_end < l)
2649 {
2650 if (s[cursor_end] == ' ')
2651 {
2652 if (cursor_end >= cursor_start)
2653 --cursor_end;
2654 else
2655 ++cursor_end;
2656 break;
2657 }
2658 if (cursor_end >= cursor_start)
2659 ++cursor_end;
2660 else
2661 --cursor_end;
2662 }
2663 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2664 d->flags |= D_DIRTY;
2665 }
2666 else
2667 {
2668 if (cursor_end == cursor_start) cursor_end = -1;
2669 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2670 }
2671 d->flags |= D_DIRTY;
2672 dclick = false;
2673 break;
2674 }
2675
2676 case MSG_WANTFOCUS:
2677 case MSG_LOSTFOCUS:
2678 case MSG_KEY:
2679 if(d->flags & (D_DISABLED|D_READONLY))
2680 break;
2681 return D_WANTFOCUS;
2682
2683 case MSG_CHAR:
2684 {
2685 if(d->flags & (D_DISABLED|D_READONLY))
2686 break;
2687 bool shifted = key_shifts & KB_SHIFT_FLAG;
2688 bool ctrl = key_shifts & KB_CTRL_CMD_FLAG;
2689 bool word_modifier = key_shifts & WORD_FLAG;
2690 bool line_modifier = key_shifts & LINE_FLAG;
2691 bool change_cursor = true;
2692 bool change_value = false;
2693 int scursor = cursor_start, ecursor = cursor_end;
2694 bool range_selected = cursor_end > -1;
2695 auto upper_c = c>>8;
2696 auto lower_c = c&0xFF;
2697
2698 if(shifted)
2699 {
2700 if(ecursor < 0)
2701 ecursor = scursor;
2702 }
2703 if(upper_c == KEY_LEFT)
2704 {
2705 if(shifted)
2706 {
2707 if(ecursor>0)
2708 --ecursor;
2709 }
2710 else
2711 {
2712 ecursor = -1;
2713 if(scursor > 0)
2714 --scursor;
2715 }
2716 }
2717 else if(upper_c == KEY_RIGHT)
2718 {
2719 if(shifted)
2720 {
2721 if(ecursor < l)
2722 ++ecursor;
2723 }
2724 else
2725 {
2726 ecursor = -1;
2727 if(scursor < l)
2728 ++scursor;
2729 }
2730 }
2731 else if(upper_c == KEY_HOME)
2732 {
2733 if(shifted)
2734 ecursor = 0;
2735 else
2736 {
2737 ecursor = -1;
2738 scursor = 0;
2739 }
2740 }
2741 else if(upper_c == KEY_END)
2742 {
2743 if(shifted)
2744 ecursor = l;
2745 else
2746 {
2747 ecursor = -1;
2748 scursor = l;
2749 }
2750 }
2751 else if(upper_c == KEY_DEL)
2752 {
2753 if(ctrl)
2754 {
2755 s[0] = 0;
2756 scursor = 0;
2757 ecursor = -1;
2758 GUI_EVENT(d, geCHANGE_VALUE);
2759 change_value = true;
2760 }
2761 else if(range_selected)
2762 {
2763 ecursor = -1;
2764 scursor = low_cursor;
2765 int ind = low_cursor, ind2 = high_cursor+1;
2766 ind2 = std::min(ind2, d->d1 - 1);
2767 while(s[ind2])
2768 s[ind++] = s[ind2++];
2769 while(s[ind])
2770 s[ind++] = 0;
2771 GUI_EVENT(d, geCHANGE_VALUE);
2772 change_value = true;
2773 }
2774 else if(scursor < l)
2775 {
2776 for(p=scursor; s[p]; p++)
2777 s[p] = s[p+1];
2778 GUI_EVENT(d, geCHANGE_VALUE);
2779 change_value = true;
2780 }
2781 }
2782 else if(upper_c == KEY_BACKSPACE)
2783 {
2784 if(line_modifier)
2785 {
2786 delete_line(s, &scursor);
2787 ecursor = -1;
2788 GUI_EVENT(d, geCHANGE_VALUE);
2789 change_value = true;
2790 }
2791 else if(word_modifier)
2792 {
2793 delete_word(s, &scursor);
2794 ecursor = -1;
2795 GUI_EVENT(d, geCHANGE_VALUE);
2796 change_value = true;
2797 }
2798 else if(range_selected)
2799 {
2800 ecursor = -1;
2801 scursor = low_cursor;
2802 size_t ind = low_cursor, ind2 = high_cursor+1;
2803 while(ind2 < l && s[ind2])
2804 s[ind++] = s[ind2++];
2805 while(s[ind])
2806 s[ind++] = 0;
2807 GUI_EVENT(d, geCHANGE_VALUE);
2808 change_value = true;
2809 }
2810 else if(scursor > 0)
2811 {
2812 --scursor;
2813 for(p=scursor; s[p]; p++)
2814 s[p] = s[p+1];
2815 GUI_EVENT(d, geCHANGE_VALUE);
2816 change_value = true;
2817 }
2818 }
2819 else if(upper_c == KEY_ENTER)
2820 {
2821 change_cursor = false;
2822 GUI_EVENT(d, geENTER);
2823 if(d->flags & D_EXIT)
2824 {
2825 object_message(d, MSG_DRAW, 0);
2826 return D_CLOSE;
2827 }
2828 else
2829 return D_O_K;
2830 }
2831 else if(upper_c == KEY_TAB)
2832 {
2833 change_cursor = false;
2834 return D_O_K;
2835 }
2836 else if (ctrl && upper_c == KEY_C)
2837 {
2838 change_cursor = false;
2839 std::ostringstream oss;
2840 if(range_selected)
2841 {
2842 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2843 {
2844 if(s[ind])
2845 oss << s[ind];
2846 }
2847 }
2848 else
2849 {
2850 if(s[scursor])
2851 oss << s[scursor];
2852 }
2853 set_al_clipboard(oss.str());
2854 }
2855 else if (ctrl && upper_c == KEY_V && clipboard_has_text())
2856 {
2857 std::string cb;
2858 if(get_al_clipboard(cb))
2859 {
2860 int ind = low_cursor, ind2 = high_cursor + 1;
2861 if (range_selected)
2862 {
2863 //Delete selected text
2864 ecursor = -1;
2865 scursor = low_cursor;
2866 while (s[ind2] && ind2 < l)
2867 s[ind++] = s[ind2++];
2868 while (s[ind])
2869 s[ind++] = 0;
2870 l = (int32_t)strlen(s);
2871 }
2872 //Move the text out of the way of the pasting
2873 int paste_len = cb.size();
2874 int paste_start = scursor;
2875 int paste_end = paste_start+paste_len;
2876 ind = strlen(s);
2877 ind2 = ind+paste_len;
2878 while(ind2 > d->d1)
2879 {
2880 --ind;
2881 --ind2;
2882 }
2883 size_t new_l = ind2;
2884 while(ind >= paste_start)
2885 {
2886 if(s[ind] || (ind&&s[ind-1]))
2887 {
2888 s[ind2] = s[ind];
2889 }
2890 --ind2; --ind;
2891 }
2892 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2893 {
2894 s[paste_start+q] = cb.at(q);
2895 }
2896 s[new_l] = 0;
2897 scursor = paste_start + paste_len;
2898 ecursor = -1;
2899 GUI_EVENT(d, geCHANGE_VALUE);
2900 change_value = true;
2901 }
2902 }
2903 else if (ctrl && upper_c == KEY_A)
2904 {
2905 cursor_start = 0;
2906 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2907 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2908 d->flags |= D_DIRTY;
2909 break;
2910 }
2911 else if(lower_c >= 32 && !ctrl)
2912 {
2913 if(range_selected)
2914 {
2915 //Delete selected text
2916 ecursor = -1;
2917 scursor = low_cursor;
2918 int ind = low_cursor, ind2 = high_cursor+1;
2919 // ind2 = std::min(ind2, d->d1);
2920 while(s[ind2] && ind2 < l)
2921 s[ind++] = s[ind2++];
2922 while(s[ind])
2923 s[ind++] = 0;
2924 l = (int32_t)strlen(s);
2925 //Type the character in its' place
2926 //(fallthrough)
2927 }
2928 if(l < d->d1)
2929 {
2930 ecursor = -1;
2931 s[l+1] = 0;
2932 size_t ind = l;
2933 while(ind >= scursor)
2934 {
2935 s[ind+1] = s[ind];
2936 if (!ind) break;
2937 --ind;
2938 }
2939
2940 s[scursor++] = lower_c;
2941
2942 GUI_EVENT(d, geCHANGE_VALUE);
2943 change_value = true;
2944 }
2945 }
2946 else
2947 return D_O_K;
2948 if(change_cursor)
2949 {
2950 cursor_end = ecursor; cursor_start = scursor;
2951 if (cursor_end == cursor_start) cursor_end = -1;
2952 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2953 }
2954 /* if we changed something, better redraw... */
2955 // Note: this still redraws when not necessary.
2956 if (change_value || change_cursor)
2957 d->flags |= D_DIRTY;
2958 return D_USED_CHAR;
2959 }
2960 }
2961 return D_O_K;
2962 }
2963
2964 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2965 {
2966 if(msg==MSG_CHAR)
2967 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2968 return D_USED_CHAR;
2969
2970 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2971 }
2972
2973 bool editproc_special_key(int32_t c)
2974 {
2975 switch(c>>8)
2976 {
2977 case KEY_LEFT: case KEY_RIGHT:
2978 case KEY_HOME: case KEY_END:
2979 case KEY_DEL: case KEY_BACKSPACE:
2980 case KEY_ENTER: case KEY_TAB:
2981 return true;
2982 }
2983 if(key_shifts & KB_CTRL_CMD_FLAG)
2984 switch(c&255)
2985 {
2986 case 'c': case 'C':
2987 return true;
2988 case 'v': case 'V':
2989 return clipboard_has_text();
2990 }
2991 return false;
2992 }
2993 bool editproc_combined_key(int32_t c)
2994 {
2995 if(key_shifts & KB_CTRL_CMD_FLAG)
2996 switch(c&255)
2997 {
2998 case 'c': case 'C':
2999 return true;
3000 case 'v': case 'V':
3001 return clipboard_has_text();
3002 }
3003 return false;
3004 }
3005 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
3006 {
3007 bool caps_paste = false;
3008 if(msg==MSG_CHAR)
3009 {
3010 if(key_shifts & KB_CTRL_CMD_FLAG)
3011 {
3012 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3013 {
3014 std::string cb;
3015 if(get_al_clipboard(cb))
3016 {
3017 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
3018 return D_USED_CHAR;
3019 if(cb.find_first_of("abcdef") != std::string::npos)
3020 caps_paste = true;
3021 }
3022 else return D_USED_CHAR;
3023 }
3024 }
3025 switch(c&255)
3026 {
3027 case '-': case '.':
3028 case '0': case '1': case '2': case '3': case '4':
3029 case '5': case '6': case '7': case '8': case '9':
3030 case 'A': case 'B': case 'C':
3031 case 'D': case 'E': case 'F':
3032 break;
3033 case 'a': case 'b': case 'c':
3034 case 'd': case 'e': case 'f':
3035 c = (c&~255)|toupper(c&255);
3036 break;
3037 default:
3038 if(!editproc_special_key(c))
3039 return D_O_K;
3040 else if(!editproc_combined_key(c))
3041 c&=~255;
3042 }
3043 }
3044
3045 auto ret = jwin_edit_proc(msg,d,c);
3046 if(caps_paste)
3047 {
3048 char* s = (char*)d->dp;
3049 caps_paste = false;
3050 for(int q = strlen(s)-1; q >= 0; --q)
3051 {
3052 switch(s[q])
3053 {
3054 case 'a': case 'b': case 'c':
3055 case 'd': case 'e': case 'f':
3056 s[q] = toupper(s[q]);
3057 caps_paste = true;
3058 break;
3059 }
3060 }
3061 if(caps_paste)
3062 {
3063 jwin_edit_proc(MSG_DRAW,d,0);
3064 }
3065 }
3066 return ret;
3067 }
3068 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
3069 {
3070 if(msg==MSG_CHAR)
3071 {
3072 if(key_shifts & KB_CTRL_CMD_FLAG)
3073 {
3074 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
3075 {
3076 std::string cb;
3077 if(get_al_clipboard(cb))
3078 {
3079 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3080 return D_USED_CHAR;
3081 }
3082 else return D_USED_CHAR;
3083 }
3084 }
3085 switch(c&255)
3086 {
3087 case '-': case '.':
3088 case '0': case '1': case '2': case '3': case '4':
3089 case '5': case '6': case '7': case '8': case '9':
3090 break;
3091 default:
3092 if(!editproc_special_key(c))
3093 return D_O_K;
3094 else if(!editproc_combined_key(c))
3095 c&=~255;
3096 }
3097 }
3098
3099 return jwin_edit_proc(msg,d,c);
3100 }
3101
3102 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3103 {
3104 if ( (atoi((char*)d->dp)) > 255 )
3105 {
3106 strcpy((char*)d->dp,"255\0");
3107 return jwin_numedit_proc(msg,d,c);
3108 }
3109 else if ( (atoi((char*)d->dp)) < 0 )
3110 {
3111 strcpy((char*)d->dp,"0\0");
3112 return jwin_numedit_proc(msg,d,c);
3113 }
3114
3115 return jwin_numedit_proc(msg,d,c);
3116 }
3117
3118 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3119 {
3120 if ( (atoi((char*)d->dp)) > 65535 )
3121 {
3122 strcpy((char*)d->dp,"65535\0");
3123 return jwin_numedit_proc(msg,d,c);
3124 }
3125 else if ( (atoi((char*)d->dp)) < 0 )
3126 {
3127 strcpy((char*)d->dp,"0\0");
3128 return jwin_numedit_proc(msg,d,c);
3129 }
3130
3131 return jwin_numedit_proc(msg,d,c);
3132 }
3133
3134 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3135 {
3136 if ( (atoi((char*)d->dp)) > 214748 )
3137 {
3138 strcpy((char*)d->dp,"214748\0");
3139 return jwin_numedit_proc(msg,d,c);
3140 }
3141 else if ( (atoi((char*)d->dp)) < -214748 )
3142 {
3143 strcpy((char*)d->dp,"-214748\0");
3144 return jwin_numedit_proc(msg,d,c);
3145 }
3146
3147 return jwin_numedit_proc(msg,d,c);
3148 }
3149
3150 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3151 {
3152 if ( (atoi((char*)d->dp)) > 32767 )
3153 {
3154 strcpy((char*)d->dp,"32767\0");
3155 return jwin_numedit_proc(msg,d,c);
3156 }
3157 else if ( (atoi((char*)d->dp)) < -32768 )
3158 {
3159 strcpy((char*)d->dp,"-32768\0");
3160 return jwin_numedit_proc(msg,d,c);
3161 }
3162
3163 return jwin_numedit_proc(msg,d,c);
3164 }
3165
3166 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3167 {
3168 if ( (atoi((char*)d->dp)) > 127 )
3169 {
3170 strcpy((char*)d->dp,"127\0");
3171 return jwin_numedit_proc(msg,d,c);
3172 }
3173 else if ( (atoi((char*)d->dp)) < -128 )
3174 {
3175 strcpy((char*)d->dp,"-128\0");
3176 return jwin_numedit_proc(msg,d,c);
3177 }
3178
3179 return jwin_numedit_proc(msg,d,c);
3180 }
3181
3182 // Special numedit procs
3183
3184 void trim_trailing_0s(char* str, bool leaveDec = false)
3185 {
3186 bool foundDec = false;
3187 for(int32_t q = 0; str[q]; ++q)
3188 {
3189 if(str[q] == '.')
3190 {
3191 foundDec = true;
3192 break;
3193 }
3194 }
3195 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3196 for(int32_t q = strlen(str)-1; q > 0; --q)
3197 {
3198 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3199 {
3200 str[q] = 0;
3201 }
3202 else if(str[q] == '.')
3203 {
3204 str[q] = 0;
3205 return;
3206 }
3207 else return;
3208 }
3209 }
3210 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3211 {
3212 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3213 d->dp = (void*)swp[d->d1&0xF];
3214 //d1 is (0xF0 = old val, 0x0F = new val)
3215 //d2 is max val
3216 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3217 DIALOG* relproc = (DIALOG*)d->dp3;
3218 GUI::TextField *tf_obj = nullptr;
3219 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3220 int32_t ret = jwin_button_proc(msg, d, c);
3221 if(d->flags & D_SELECTED) //On selection
3222 {
3223 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3224 d->dp = (void*)swp[d->d1&0xF];
3225 d->flags &= ~D_SELECTED;
3226 if(tf_obj) tf_obj->refresh_cb_swap();
3227 if(relproc)
3228 {
3229 object_message(relproc, MSG_DRAW, 0);
3230 }
3231 object_message(d, MSG_DRAW, 0);
3232 }
3233 return ret;
3234 }
3235 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3236 {
3237 DIALOG* swapbtn;
3238 if(d->flags&D_NEW_GUI)
3239 {
3240 swapbtn = d+1;
3241 }
3242 else swapbtn = (DIALOG*)d->dp3;
3243 if(!swapbtn) return D_O_K;
3244 if(msg==MSG_START) //Setup the swapbtn
3245 {
3246 d->bg = 0;
3247 swapbtn->d2 = 2; //Max states
3248 auto ty = swapbtn->d1&0xF;
3249 if(unsigned(ty) > swapbtn->d2)
3250 swapbtn->d1 &= ~0xF;
3251 swapbtn->dp3 = (void*)d;
3252 }
3253 int32_t ret = D_O_K;
3254 int32_t ntype = swapbtn->d1&0xF,
3255 otype = swapbtn->d1>>4;
3256
3257 char* str = (char*)d->dp;
3258 int32_t v = 0;
3259 if(msg == MSG_START)
3260 v = d->fg;
3261 else switch(otype)
3262 {
3263 case nswapDEC:
3264 v = atoi(str);
3265 break;
3266 case nswapHEX:
3267 v = zc_xtoi(str);
3268 break;
3269 }
3270 byte b;
3271 if ( v > 255 )
3272 b=255;
3273 else if ( v < 0 )
3274 b=0;
3275 else b = (byte)v;
3276 if(msg==MSG_CHAR && ((c&255)=='-'))
3277 {
3278 //unsigned//b = -b;
3279 c &= ~255;
3280 }
3281 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3282 {
3283 switch(ntype)
3284 {
3285 case nswapDEC:
3286 sprintf(str, "%d", b);
3287 break;
3288 case nswapHEX:
3289 sprintf(str, "%X", b);
3290 break;
3291 }
3292 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3293 }
3294
3295 if(d->fg != b)
3296 {
3297 d->fg = b; //Store numeric data
3298 GUI_EVENT(d, geUPDATE_SWAP);
3299 }
3300 switch(ntype)
3301 {
3302 case nswapDEC:
3303 d->d1 = 3; //3 digits max
3304 ret |= jwin_numedit_proc(msg, d, c);
3305 break;
3306 case nswapHEX:
3307 d->d1 = 2; //2 digits max
3308 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3309 c = (c&~255) | (toupper(c&255));
3310 ret |= jwin_hexedit_proc(msg, d, c);
3311 break;
3312 }
3313
3314 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3315
3316 return ret;
3317 }
3318 #define INC_TF_CURSORS(val,inc,max) \
3319 do \
3320 { \
3321 int32_t scursor = (val & 0xFFFF)+inc; \
3322 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3323 bool valid_ecursor = ecursor != 0xFFFF; \
3324 if(valid_ecursor) ecursor += inc; \
3325 if(inc < 0) \
3326 { \
3327 if(scursor < 0) scursor = 0; \
3328 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3329 } \
3330 else \
3331 { \
3332 if(scursor > max) scursor = max; \
3333 if(valid_ecursor && ecursor > max) ecursor = max; \
3334 } \
3335 val = scursor | (ecursor<<16); \
3336 } while(false)
3337 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3338 {
3339 const size_t maxlen = 7;
3340 DIALOG* swapbtn;
3341 if(d->flags&D_NEW_GUI)
3342 {
3343 swapbtn = d+1;
3344 }
3345 else swapbtn = (DIALOG*)d->dp3;
3346 if(!swapbtn) return D_O_K;
3347 if(msg==MSG_START) //Setup the swapbtn
3348 {
3349 d->bg = 0;
3350 swapbtn->d2 = 2; //Max states
3351 auto ty = swapbtn->d1&0xF;
3352 if(unsigned(ty) > swapbtn->d2)
3353 swapbtn->d1 &= ~0xF;
3354 swapbtn->dp3 = (void*)d;
3355 }
3356 int32_t ret = D_O_K;
3357 int32_t ntype = swapbtn->d1&0xF,
3358 otype = swapbtn->d1>>4;
3359
3360 char* str = (char*)d->dp;
3361 int32_t v = 0;
3362 if(msg == MSG_START)
3363 v = d->fg;
3364 else switch(otype)
3365 {
3366 case nswapDEC:
3367 v = atoi(str);
3368 break;
3369 case nswapHEX:
3370 v = zc_xtoi(str);
3371 break;
3372 }
3373 int16_t b;
3374 if ( v > 32767 )
3375 b=32767;
3376 else if ( v < -32768 )
3377 b=-32768;
3378 else b = (int16_t)v;
3379 bool queued_neg = d->bg;
3380 if(msg==MSG_CHAR && ((c&255)=='-'))
3381 {
3382 if(b)
3383 {
3384 b = -b;
3385 v = b;
3386 if(b<0)
3387 {
3388 if(str[0] != '-')
3389 {
3390 char buf[16] = {0};
3391 strcpy(buf, str);
3392 sprintf(str, "-%s", buf);
3393 INC_TF_CURSORS(d->d2,1,strlen(str));
3394 }
3395 }
3396 else if(str[0] == '-')
3397 {
3398 char buf[16] = {0};
3399 strcpy(buf, str);
3400 sprintf(str, "%s", buf+1);
3401 INC_TF_CURSORS(d->d2,-1,strlen(str));
3402 }
3403 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3404 }
3405 else queued_neg = !queued_neg; //queue the negative
3406 c &= ~255;
3407 ret |= D_USED_CHAR;
3408 }
3409 if(b && queued_neg)
3410 {
3411 //b = -b; //actually, 'atoi' handles it for us.....
3412 queued_neg = false;
3413 }
3414 if(bool(d->bg) != queued_neg)
3415 {
3416 d->bg = queued_neg;
3417 if(queued_neg)
3418 {
3419 if(str[0] != '-')
3420 {
3421 char buf[16] = {0};
3422 strcpy(buf, str);
3423 sprintf(str, "-%s", buf);
3424 INC_TF_CURSORS(d->d2,1,strlen(str));
3425 }
3426 }
3427 else if(!b && str[0] == '-')
3428 {
3429 char buf[16] = {0};
3430 strcpy(buf, str);
3431 sprintf(str, "%s", buf+1);
3432 INC_TF_CURSORS(d->d2,-1,strlen(str));
3433 }
3434 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3435 }
3436 if(v != b || otype != ntype || msg == MSG_START)
3437 {
3438 switch(ntype)
3439 {
3440 case nswapDEC:
3441 sprintf(str, "%d", b);
3442 break;
3443 case nswapHEX:
3444 if(b<0)
3445 sprintf(str, "-%X", -b);
3446 else sprintf(str, "%X", b);
3447 break;
3448 }
3449 d->d2 = 0xFFFF0000|strlen(str);
3450 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3451 }
3452
3453 if(d->fg != b)
3454 {
3455 d->fg = b; //Store numeric data
3456 GUI_EVENT(d, geUPDATE_SWAP);
3457 }
3458 bool rev_d2 = false;
3459 int32_t old_d2 = d->d2;
3460 int32_t ref_d2;
3461 if(msg == MSG_CHAR && queued_neg)
3462 {
3463 auto scursor = d->d2 & 0xFFFF;
3464 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3465 if(!scursor)
3466 {
3467 rev_d2 = true;
3468 INC_TF_CURSORS(d->d2,1,strlen(str));
3469 ref_d2 = d->d2;
3470 }
3471 }
3472 switch(ntype)
3473 {
3474 case nswapDEC:
3475 d->d1 = 6; //6 digits max (incl '-')
3476 ret |= jwin_numedit_proc(msg, d, c);
3477 break;
3478 case nswapHEX:
3479 d->d1 = 5; //5 digits max (incl '-')
3480 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3481 c = (c&~255) | (toupper(c&255));
3482 ret |= jwin_hexedit_proc(msg, d, c);
3483 break;
3484 }
3485 if(rev_d2 && ref_d2 == d->d2)
3486 {
3487 d->d2 = old_d2;
3488 }
3489
3490 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3491
3492 return ret;
3493 }
3494 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3495 {
3496 const size_t maxlen = 13;
3497 DIALOG* swapbtn;
3498 if(d->flags&D_NEW_GUI)
3499 {
3500 swapbtn = d+1;
3501 }
3502 else swapbtn = (DIALOG*)d->dp3;
3503 if(!swapbtn) return D_O_K;
3504 if(msg==MSG_START) //Setup the swapbtn
3505 {
3506 d->bg = 0;
3507 swapbtn->d2 = 4; //Max states
3508 auto ty = swapbtn->d1&0xF;
3509 if(unsigned(ty) > swapbtn->d2)
3510 swapbtn->d1 &= ~0xF;
3511 swapbtn->dp3 = (void*)d;
3512 }
3513 int32_t ret = D_O_K;
3514 int32_t ntype = swapbtn->d1&0xF,
3515 otype = swapbtn->d1>>4;
3516
3517 char* str = (char*)d->dp;
3518 int64_t v = 0;
3519 if(msg == MSG_START)
3520 v = d->fg;
3521 else switch(otype)
3522 {
3523 case nswapDEC:
3524 if(char *ptr = strchr(str, '.'))
3525 {
3526 char tempstr[32] = {0};
3527 strcpy(tempstr, str);
3528 for(int32_t q = 0; q < 4; ++q)
3529 tempstr[strlen(str)+q]='0';
3530 ptr = strchr(tempstr, '.');
3531 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3532 v = atoi(tempstr);
3533 v *= 10000;
3534 if(tempstr[0] == '-')
3535 v -= atoi(ptr);
3536 else v += atoi(ptr);
3537 }
3538 else
3539 {
3540 v = atoi(str);
3541 v *= 10000;
3542 }
3543 break;
3544 case nswapHEX:
3545 if(char *ptr = strchr(str, '.'))
3546 {
3547 char tempstr[32] = {0};
3548 strcpy(tempstr, str);
3549 for(int32_t q = 0; q < 4; ++q)
3550 tempstr[strlen(str)+q]='0';
3551 ptr = strchr(tempstr, '.');
3552 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3553 v = zc_xtoi(tempstr);
3554 v *= 10000;
3555 if(tempstr[0] == '-')
3556 v -= atoi(ptr);
3557 else v += atoi(ptr);
3558 }
3559 else
3560 {
3561 v = zc_xtoi(str);
3562 v *= 10000;
3563 }
3564 break;
3565 case nswapLDEC:
3566 v = zc_atoi64(str);
3567 break;
3568 case nswapLHEX:
3569 v = zc_xtoi64(str);
3570 break;
3571 }
3572 int32_t b;
3573 if ( v > 2147483647 )
3574 b=2147483647;
3575 else if ( v < INT_MIN )
3576 b=INT_MIN;
3577 else b = (int32_t)v;
3578 bool queued_neg = d->bg;
3579 if(msg==MSG_CHAR && ((c&255)=='-'))
3580 {
3581 if(b)
3582 {
3583 if(b==INT_MIN)
3584 ++b;
3585 b = -b;
3586 v = b;
3587 if(b<0)
3588 {
3589 if(str[0] != '-')
3590 {
3591 char buf[16] = {0};
3592 strcpy(buf, str);
3593 sprintf(str, "-%s", buf);
3594 INC_TF_CURSORS(d->d2,1,strlen(str));
3595 }
3596 }
3597 else if(str[0] == '-')
3598 {
3599 char buf[16] = {0};
3600 strcpy(buf, str);
3601 sprintf(str, "%s", buf+1);
3602 INC_TF_CURSORS(d->d2,-1,strlen(str));
3603 }
3604 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3605 }
3606 else queued_neg = !queued_neg; //queue negative
3607 c &= ~255;
3608 ret |= D_USED_CHAR;
3609 }
3610 if(b && queued_neg)
3611 {
3612 //b = -b; //actually, 'atoi' handles it for us.....
3613 queued_neg = false;
3614 }
3615 if(bool(d->bg) != queued_neg)
3616 {
3617 d->bg = queued_neg;
3618 if(queued_neg)
3619 {
3620 if(str[0] != '-')
3621 {
3622 char buf[16] = {0};
3623 strcpy(buf, str);
3624 sprintf(str, "-%s", buf);
3625 INC_TF_CURSORS(d->d2,1,strlen(str));
3626 }
3627 }
3628 else if(!b && str[0] == '-')
3629 {
3630 char buf[16] = {0};
3631 strcpy(buf, str);
3632 sprintf(str, "%s", buf+1);
3633 INC_TF_CURSORS(d->d2,-1,strlen(str));
3634 }
3635 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3636 }
3637 if(v != b || otype != ntype || msg == MSG_START)
3638 {
3639 switch(ntype)
3640 {
3641 case nswapDEC:
3642 if(b < 0)
3643 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3644 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3645 trim_trailing_0s(str);
3646 break;
3647 case nswapHEX:
3648 if(b<0)
3649 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3650 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3651 trim_trailing_0s(str);
3652 break;
3653 case nswapLDEC:
3654 sprintf(str, "%d", b);
3655 break;
3656 case nswapLHEX:
3657 if(b<0)
3658 sprintf(str, "-%X", -b);
3659 else sprintf(str, "%X", b);
3660 break;
3661 }
3662 d->d2 = 0xFFFF0000|strlen(str);
3663 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3664 }
3665 if(d->fg != b)
3666 {
3667 d->fg = b; //Store numeric data
3668 GUI_EVENT(d, geUPDATE_SWAP);
3669 }
3670 if(msg==MSG_CHAR && ((c&255)=='.'))
3671 {
3672 if(ntype >= nswapLDEC) //No '.' in long modes
3673 c&=~255;
3674 else
3675 {
3676 for(int32_t q = 0; str[q]; ++q)
3677 {
3678 if(str[q] == '.') //Only one '.'
3679 {
3680 c&=~255;
3681 break;
3682 }
3683 }
3684 }
3685 }
3686 bool rev_d2 = false;
3687 int32_t old_d2 = d->d2;
3688 int32_t ref_d2;
3689 if(msg == MSG_CHAR && queued_neg)
3690 {
3691 auto scursor = d->d2 & 0xFFFF;
3692 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3693 if(!scursor)
3694 {
3695 rev_d2 = true;
3696 INC_TF_CURSORS(d->d2,1,strlen(str));
3697 ref_d2 = d->d2;
3698 }
3699 }
3700 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3701 switch(ntype)
3702 {
3703 case nswapDEC:
3704 d->d1 = 12; //12 digits max (incl '-', '.')
3705 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3706 {
3707 int32_t p = 0;
3708 for(int32_t q = 0; str[q]; ++q)
3709 {
3710 if(str[q]=='.')
3711 {
3712 if((d->d2&0x0000FFFF) <= q)
3713 break; //typing before the '.'
3714 ++p;
3715 }
3716 else if(p) ++p;
3717 }
3718 if(p>=5) //too many chars after '.'
3719 c&=~255;
3720 }
3721 ret |= jwin_numedit_proc(msg, d, c);
3722 break;
3723 case nswapHEX:
3724 d->d1 = 11; //11 digits max (incl '-', '.')
3725 if(msg==MSG_CHAR && !editproc_special_key(c))
3726 {
3727 if(!((c&255)=='.'||isxdigit(c&255)))
3728 c&=~255;
3729 else if(isxdigit(c&255) && !isdigit(c&255))
3730 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3731 {
3732 if(str[q] == '.') //No hex digits to the right of the '.'
3733 {
3734 c&=~255;
3735 break;
3736 }
3737 }
3738 if((c&255) && !areaselect)
3739 {
3740 int32_t p = 0;
3741 for(int32_t q = 0; str[q]; ++q)
3742 {
3743 if(str[q]=='.')
3744 {
3745 if((d->d2&0x0000FFFF) <= q)
3746 break; //typing before the '.'
3747 ++p;
3748 }
3749 else if(p) ++p;
3750 }
3751 if(p>=5) //too many chars after '.'
3752 c&=~255;
3753 }
3754 if(isalpha(c&255)) //always capitalize
3755 c = (c&~255) | (toupper(c&255));
3756 }
3757 ret |= jwin_hexedit_proc(msg, d, c);
3758 break;
3759 case nswapLDEC:
3760 d->d1 = 11; //11 digits max (incl '-')
3761 ret |= jwin_numedit_proc(msg, d, c);
3762 break;
3763 case nswapLHEX:
3764 d->d1 = 9; //9 digits max (incl '-')
3765 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3766 c = (c&~255) | (toupper(c&255));
3767 ret |= jwin_hexedit_proc(msg, d, c);
3768 break;
3769 }
3770 if(rev_d2 && ref_d2 == d->d2)
3771 {
3772 d->d2 = old_d2;
3773 }
3774
3775 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3776
3777 return ret;
3778 }
3779 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3780 {
3781 const size_t maxlen = 7;
3782 DIALOG* swapbtn;
3783 if(d->flags&D_NEW_GUI)
3784 {
3785 swapbtn = d+1;
3786 }
3787 else swapbtn = (DIALOG*)d->dp3;
3788 if(!swapbtn) return D_O_K;
3789 if(msg==MSG_START) //Setup the swapbtn
3790 {
3791 d->bg = 0;
3792 swapbtn->d2 = 2; //Max states
3793 auto ty = swapbtn->d1&0xF;
3794 if(unsigned(ty) > swapbtn->d2)
3795 swapbtn->d1 &= ~0xF;
3796 swapbtn->dp3 = (void*)d;
3797 }
3798 int32_t ret = D_O_K;
3799 int32_t ntype = swapbtn->d1&0xF,
3800 otype = swapbtn->d1>>4;
3801
3802 char* str = (char*)d->dp;
3803 int64_t v = 0;
3804 if(msg == MSG_START)
3805 v = d->fg;
3806 else switch(otype)
3807 {
3808 case nswapDEC:
3809 v = atoi(str);
3810 v *= 10000;
3811 break;
3812 case nswapHEX:
3813 v = zc_xtoi(str);
3814 v *= 10000;
3815 break;
3816 }
3817 int32_t b;
3818 if ( v > 2147480000 )
3819 b=2147480000;
3820 else if ( v < -2147480000 )
3821 b=-2147480000;
3822 else b = (int32_t)v;
3823 bool queued_neg = d->bg;
3824 if(msg==MSG_CHAR && ((c&255)=='-'))
3825 {
3826 if(b)
3827 {
3828 if(b==INT_MIN)
3829 ++b;
3830 b = -b;
3831 v = b;
3832 if(b<0)
3833 {
3834 if(str[0] != '-')
3835 {
3836 char buf[16] = {0};
3837 strcpy(buf, str);
3838 sprintf(str, "-%s", buf);
3839 INC_TF_CURSORS(d->d2,1,strlen(str));
3840 }
3841 }
3842 else if(str[0] == '-')
3843 {
3844 char buf[16] = {0};
3845 strcpy(buf, str);
3846 sprintf(str, "%s", buf+1);
3847 INC_TF_CURSORS(d->d2,-1,strlen(str));
3848 }
3849 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3850 }
3851 else queued_neg = !queued_neg; //queue negative
3852 c &= ~255;
3853 ret |= D_USED_CHAR;
3854 }
3855 if(b && queued_neg)
3856 {
3857 //b = -b; //actually, 'atoi' handles it for us.....
3858 queued_neg = false;
3859 }
3860 if(bool(d->bg) != queued_neg)
3861 {
3862 d->bg = queued_neg;
3863 if(queued_neg)
3864 {
3865 if(str[0] != '-')
3866 {
3867 char buf[16] = {0};
3868 strcpy(buf, str);
3869 sprintf(str, "-%s", buf);
3870 INC_TF_CURSORS(d->d2,1,strlen(str));
3871 }
3872 }
3873 else if(!b && str[0] == '-')
3874 {
3875 char buf[16] = {0};
3876 strcpy(buf, str);
3877 sprintf(str, "%s", buf+1);
3878 INC_TF_CURSORS(d->d2,-1,strlen(str));
3879 }
3880 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3881 }
3882 if(v != b || otype != ntype || msg == MSG_START)
3883 {
3884 switch(ntype)
3885 {
3886 case nswapDEC:
3887 if(b < 0)
3888 sprintf(str, "-%ld", abs(b/10000L));
3889 else sprintf(str, "%ld", b/10000L);
3890 break;
3891 case nswapHEX:
3892 if(b<0)
3893 sprintf(str, "-%lX", abs(b/10000L));
3894 else sprintf(str, "%lX", b/10000L);
3895 break;
3896 }
3897 d->d2 = 0xFFFF0000|strlen(str);
3898 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3899 }
3900 if(d->fg != b)
3901 {
3902 d->fg = b; //Store numeric data
3903 GUI_EVENT(d, geUPDATE_SWAP);
3904 }
3905 if(msg==MSG_CHAR && ((c&255)=='.'))
3906 {
3907 c&=~255; //no '.' in nodec version
3908 }
3909 bool rev_d2 = false;
3910 int32_t old_d2 = d->d2;
3911 int32_t ref_d2;
3912 if(msg == MSG_CHAR && queued_neg)
3913 {
3914 auto scursor = d->d2 & 0xFFFF;
3915 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3916 if(!scursor)
3917 {
3918 rev_d2 = true;
3919 INC_TF_CURSORS(d->d2,1,strlen(str));
3920 ref_d2 = d->d2;
3921 }
3922 }
3923 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3924 switch(ntype)
3925 {
3926 case nswapDEC:
3927 d->d1 = 7; //7 digits max (incl '-')
3928 ret |= jwin_numedit_proc(msg, d, c);
3929 break;
3930 case nswapHEX:
3931 d->d1 = 6; //6 digits max (incl '-')
3932 if(msg==MSG_CHAR && !editproc_special_key(c))
3933 {
3934 if(!isxdigit(c&255))
3935 c&=~255;
3936 if(isalpha(c&255)) //always capitalize
3937 c = (c&~255) | (toupper(c&255));
3938 }
3939 ret |= jwin_hexedit_proc(msg, d, c);
3940 break;
3941 }
3942 if(rev_d2 && ref_d2 == d->d2)
3943 {
3944 d->d2 = old_d2;
3945 }
3946
3947 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3948
3949 return ret;
3950 }
3951 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3952 {
3953 const size_t maxlen = 13;
3954 DIALOG* swapbtn;
3955 ASSERT(d->flags&D_NEW_GUI);
3956 swapbtn = d+1;
3957 if(!swapbtn) return D_O_K;
3958 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3959 if(!tf_obj) return D_O_K;
3960 if(msg==MSG_START) //Setup the swapbtn
3961 {
3962 d->bg = 0;
3963 swapbtn->d2 = 5; //Max states
3964 auto ty = swapbtn->d1&0xF;
3965 if(unsigned(ty) > swapbtn->d2)
3966 swapbtn->d1 &= ~0xF;
3967 swapbtn->dp3 = (void*)d;
3968 }
3969 int32_t ret = D_O_K;
3970 int32_t ntype = swapbtn->d1&0xF,
3971 otype = swapbtn->d1>>4;
3972 if(otype==nswapBOOL || ntype == nswapBOOL)
3973 {
3974 if(otype != ntype)
3975 {
3976 tf_obj->refresh_cb_swap();
3977 }
3978 if(ntype == nswapBOOL)
3979 {
3980 swapbtn->d1 = (ntype<<4)|ntype;
3981 return D_O_K;
3982 }
3983 }
3984
3985 char* str = (char*)d->dp;
3986 int64_t v = 0;
3987 if(msg == MSG_START)
3988 v = d->fg;
3989 else switch(otype)
3990 {
3991 case nswapDEC:
3992 if(char *ptr = strchr(str, '.'))
3993 {
3994 char tempstr[32] = {0};
3995 strcpy(tempstr, str);
3996 for(int32_t q = 0; q < 4; ++q)
3997 tempstr[strlen(str)+q]='0';
3998 ptr = strchr(tempstr, '.');
3999 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4000 v = atoi(tempstr);
4001 v *= 10000;
4002 if(tempstr[0] == '-')
4003 v -= atoi(ptr);
4004 else v += atoi(ptr);
4005 }
4006 else
4007 {
4008 v = atoi(str);
4009 v *= 10000;
4010 }
4011 break;
4012 case nswapHEX:
4013 if(char *ptr = strchr(str, '.'))
4014 {
4015 char tempstr[32] = {0};
4016 strcpy(tempstr, str);
4017 for(int32_t q = 0; q < 4; ++q)
4018 tempstr[strlen(str)+q]='0';
4019 ptr = strchr(tempstr, '.');
4020 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4021 v = zc_xtoi(tempstr);
4022 v *= 10000;
4023 if(tempstr[0] == '-')
4024 v -= atoi(ptr);
4025 else v += atoi(ptr);
4026 }
4027 else
4028 {
4029 v = zc_xtoi(str);
4030 v *= 10000;
4031 }
4032 break;
4033 case nswapLDEC:
4034 v = zc_atoi64(str);
4035 break;
4036 case nswapLHEX:
4037 v = zc_xtoi64(str);
4038 break;
4039 case nswapBOOL:
4040 v = d->fg;
4041 break;
4042 }
4043 int32_t b;
4044 if ( v > 2147483647 )
4045 b=2147483647;
4046 else if ( v < INT_MIN )
4047 b=INT_MIN;
4048 else b = (int32_t)v;
4049 bool queued_neg = d->bg;
4050 if(msg==MSG_CHAR && ((c&255)=='-'))
4051 {
4052 if(b)
4053 {
4054 if(b==INT_MIN)
4055 ++b;
4056 b = -b;
4057 v = b;
4058 if(b<0)
4059 {
4060 if(str[0] != '-')
4061 {
4062 char buf[16] = {0};
4063 strcpy(buf, str);
4064 sprintf(str, "-%s", buf);
4065 INC_TF_CURSORS(d->d2,1,strlen(str));
4066 }
4067 }
4068 else if(str[0] == '-')
4069 {
4070 char buf[16] = {0};
4071 strcpy(buf, str);
4072 sprintf(str, "%s", buf+1);
4073 INC_TF_CURSORS(d->d2,-1,strlen(str));
4074 }
4075 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4076 }
4077 else queued_neg = !queued_neg; //queue negative
4078 c &= ~255;
4079 ret |= D_USED_CHAR;
4080 }
4081 if(b && queued_neg)
4082 {
4083 //b = -b; //actually, 'atoi' handles it for us.....
4084 queued_neg = false;
4085 }
4086 if(bool(d->bg) != queued_neg)
4087 {
4088 d->bg = queued_neg;
4089 if(queued_neg)
4090 {
4091 if(str[0] != '-')
4092 {
4093 char buf[16] = {0};
4094 strcpy(buf, str);
4095 sprintf(str, "-%s", buf);
4096 INC_TF_CURSORS(d->d2,1,strlen(str));
4097 }
4098 }
4099 else if(!b && str[0] == '-')
4100 {
4101 char buf[16] = {0};
4102 strcpy(buf, str);
4103 sprintf(str, "%s", buf+1);
4104 INC_TF_CURSORS(d->d2,-1,strlen(str));
4105 }
4106 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4107 }
4108 if(v != b || otype != ntype || msg == MSG_START)
4109 {
4110 switch(ntype)
4111 {
4112 case nswapDEC:
4113 if(b < 0)
4114 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4115 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4116 trim_trailing_0s(str);
4117 break;
4118 case nswapHEX:
4119 if(b<0)
4120 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4121 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4122 trim_trailing_0s(str);
4123 break;
4124 case nswapLDEC:
4125 sprintf(str, "%d", b);
4126 break;
4127 case nswapLHEX:
4128 if(b<0)
4129 sprintf(str, "-%X", -b);
4130 else sprintf(str, "%X", b);
4131 break;
4132 }
4133 d->d2 = 0xFFFF0000|strlen(str);
4134 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4135 }
4136 if(d->fg != b)
4137 {
4138 d->fg = b; //Store numeric data
4139 GUI_EVENT(d, geUPDATE_SWAP);
4140 }
4141 if(msg==MSG_CHAR && ((c&255)=='.'))
4142 {
4143 if(ntype >= nswapLDEC) //No '.' in long modes
4144 c&=~255;
4145 else
4146 {
4147 for(int32_t q = 0; str[q]; ++q)
4148 {
4149 if(str[q] == '.') //Only one '.'
4150 {
4151 c&=~255;
4152 break;
4153 }
4154 }
4155 }
4156 }
4157 bool rev_d2 = false;
4158 int32_t old_d2 = d->d2;
4159 int32_t ref_d2;
4160 if(msg == MSG_CHAR && queued_neg)
4161 {
4162 auto scursor = d->d2 & 0xFFFF;
4163 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4164 if(!scursor)
4165 {
4166 rev_d2 = true;
4167 INC_TF_CURSORS(d->d2,1,strlen(str));
4168 ref_d2 = d->d2;
4169 }
4170 }
4171 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4172 switch(ntype)
4173 {
4174 case nswapDEC:
4175 d->d1 = 12; //12 digits max (incl '-', '.')
4176 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4177 {
4178 int32_t p = 0;
4179 for(int32_t q = 0; str[q]; ++q)
4180 {
4181 if(str[q]=='.')
4182 {
4183 if((d->d2&0x0000FFFF) <= q)
4184 break; //typing before the '.'
4185 ++p;
4186 }
4187 else if(p) ++p;
4188 }
4189 if(p>=5) //too many chars after '.'
4190 c&=~255;
4191 }
4192 ret |= jwin_numedit_proc(msg, d, c);
4193 break;
4194 case nswapHEX:
4195 d->d1 = 11; //11 digits max (incl '-', '.')
4196 if(msg==MSG_CHAR && !editproc_special_key(c))
4197 {
4198 if(!((c&255)=='.'||isxdigit(c&255)))
4199 c&=~255;
4200 else if(isxdigit(c&255) && !isdigit(c&255))
4201 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4202 {
4203 if(str[q] == '.') //No hex digits to the right of the '.'
4204 {
4205 c&=~255;
4206 break;
4207 }
4208 }
4209 if((c&255) && !areaselect)
4210 {
4211 int32_t p = 0;
4212 for(int32_t q = 0; str[q]; ++q)
4213 {
4214 if(str[q]=='.')
4215 {
4216 if((d->d2&0x0000FFFF) <= q)
4217 break; //typing before the '.'
4218 ++p;
4219 }
4220 else if(p) ++p;
4221 }
4222 if(p>=5) //too many chars after '.'
4223 c&=~255;
4224 }
4225 if(isalpha(c&255)) //always capitalize
4226 c = (c&~255) | (toupper(c&255));
4227 }
4228 ret |= jwin_hexedit_proc(msg, d, c);
4229 break;
4230 case nswapLDEC:
4231 d->d1 = 11; //11 digits max (incl '-')
4232 ret |= jwin_numedit_proc(msg, d, c);
4233 break;
4234 case nswapLHEX:
4235 d->d1 = 9; //9 digits max (incl '-')
4236 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4237 c = (c&~255) | (toupper(c&255));
4238 ret |= jwin_hexedit_proc(msg, d, c);
4239 break;
4240 }
4241 if(rev_d2 && ref_d2 == d->d2)
4242 {
4243 d->d2 = old_d2;
4244 }
4245
4246 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4247
4248 if(msg==MSG_START)
4249 tf_obj->refresh_cb_swap();
4250
4251 return ret;
4252 }
4253 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4254 {
4255 const size_t maxlen = 13;
4256 ASSERT(d->flags&D_NEW_GUI);
4257 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4258 if(!tf_obj) return D_O_K;
4259 int32_t ret = D_O_K;
4260 int32_t type = tf_obj->getSwapType();
4261
4262 char* str = (char*)d->dp;
4263 int64_t v = 0;
4264 if(msg == MSG_START)
4265 v = d->fg;
4266 else switch(type)
4267 {
4268 case nswapDEC:
4269 if(char *ptr = strchr(str, '.'))
4270 {
4271 char tempstr[32] = {0};
4272 strcpy(tempstr, str);
4273 for(int32_t q = 0; q < 4; ++q)
4274 tempstr[strlen(str)+q]='0';
4275 ptr = strchr(tempstr, '.');
4276 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4277 v = atoi(tempstr);
4278 v *= 10000;
4279 if(tempstr[0] == '-')
4280 v -= atoi(ptr);
4281 else v += atoi(ptr);
4282 }
4283 else
4284 {
4285 v = atoi(str);
4286 v *= 10000;
4287 }
4288 break;
4289 case nswapHEX:
4290 if(char *ptr = strchr(str, '.'))
4291 {
4292 char tempstr[32] = {0};
4293 strcpy(tempstr, str);
4294 for(int32_t q = 0; q < 4; ++q)
4295 tempstr[strlen(str)+q]='0';
4296 ptr = strchr(tempstr, '.');
4297 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4298 v = zc_xtoi(tempstr);
4299 v *= 10000;
4300 if(tempstr[0] == '-')
4301 v -= atoi(ptr);
4302 else v += atoi(ptr);
4303 }
4304 else
4305 {
4306 v = zc_xtoi(str);
4307 v *= 10000;
4308 }
4309 break;
4310 case nswapLDEC:
4311 v = zc_atoi64(str);
4312 break;
4313 case nswapLHEX:
4314 v = zc_xtoi64(str);
4315 break;
4316 case nswapBOOL:
4317 v = d->fg;
4318 break;
4319 }
4320 int32_t b;
4321 if ( v > 2147483647 )
4322 b=2147483647;
4323 else if ( v < INT_MIN )
4324 b=INT_MIN;
4325 else b = (int32_t)v;
4326 bool queued_neg = d->bg;
4327 if(msg==MSG_CHAR && ((c&255)=='-'))
4328 {
4329 if(b)
4330 {
4331 if(b==INT_MIN)
4332 ++b;
4333 b = -b;
4334 v = b;
4335 if(b<0)
4336 {
4337 if(str[0] != '-')
4338 {
4339 char buf[16] = {0};
4340 strcpy(buf, str);
4341 sprintf(str, "-%s", buf);
4342 INC_TF_CURSORS(d->d2,1,strlen(str));
4343 }
4344 }
4345 else if(str[0] == '-')
4346 {
4347 char buf[16] = {0};
4348 strcpy(buf, str);
4349 sprintf(str, "%s", buf+1);
4350 INC_TF_CURSORS(d->d2,-1,strlen(str));
4351 }
4352 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4353 }
4354 else queued_neg = !queued_neg; //queue negative
4355 c &= ~255;
4356 ret |= D_USED_CHAR;
4357 }
4358 if(b && queued_neg)
4359 {
4360 //b = -b; //actually, 'atoi' handles it for us.....
4361 queued_neg = false;
4362 }
4363 if(bool(d->bg) != queued_neg)
4364 {
4365 d->bg = queued_neg;
4366 if(queued_neg)
4367 {
4368 if(str[0] != '-')
4369 {
4370 char buf[16] = {0};
4371 strcpy(buf, str);
4372 sprintf(str, "-%s", buf);
4373 INC_TF_CURSORS(d->d2,1,strlen(str));
4374 }
4375 }
4376 else if(!b && str[0] == '-')
4377 {
4378 char buf[16] = {0};
4379 strcpy(buf, str);
4380 sprintf(str, "%s", buf+1);
4381 INC_TF_CURSORS(d->d2,-1,strlen(str));
4382 }
4383 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4384 }
4385 if(v != b || msg == MSG_START)
4386 {
4387 switch(type)
4388 {
4389 case nswapDEC:
4390 if(b < 0)
4391 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4392 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4393 trim_trailing_0s(str);
4394 break;
4395 case nswapHEX:
4396 if(b<0)
4397 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4398 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4399 trim_trailing_0s(str);
4400 break;
4401 case nswapLDEC:
4402 sprintf(str, "%d", b);
4403 break;
4404 case nswapLHEX:
4405 if(b<0)
4406 sprintf(str, "-%X", -b);
4407 else sprintf(str, "%X", b);
4408 break;
4409 }
4410 d->d2 = 0xFFFF0000|strlen(str);
4411 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4412 }
4413 if(d->fg != b)
4414 {
4415 d->fg = b; //Store numeric data
4416 GUI_EVENT(d, geUPDATE_SWAP);
4417 }
4418 if(msg==MSG_CHAR && ((c&255)=='.'))
4419 {
4420 if(type >= nswapLDEC) //No '.' in long modes
4421 c&=~255;
4422 else
4423 {
4424 for(int32_t q = 0; str[q]; ++q)
4425 {
4426 if(str[q] == '.') //Only one '.'
4427 {
4428 c&=~255;
4429 break;
4430 }
4431 }
4432 }
4433 }
4434 bool rev_d2 = false;
4435 int32_t old_d2 = d->d2;
4436 int32_t ref_d2;
4437 if(msg == MSG_CHAR && queued_neg)
4438 {
4439 auto scursor = d->d2 & 0xFFFF;
4440 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4441 if(!scursor)
4442 {
4443 rev_d2 = true;
4444 INC_TF_CURSORS(d->d2,1,strlen(str));
4445 ref_d2 = d->d2;
4446 }
4447 }
4448 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4449 switch(type)
4450 {
4451 case nswapDEC:
4452 d->d1 = 12; //12 digits max (incl '-', '.')
4453 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4454 {
4455 int32_t p = 0;
4456 for(int32_t q = 0; str[q]; ++q)
4457 {
4458 if(str[q]=='.')
4459 {
4460 if((d->d2&0x0000FFFF) <= q)
4461 break; //typing before the '.'
4462 ++p;
4463 }
4464 else if(p) ++p;
4465 }
4466 if(p>=5) //too many chars after '.'
4467 c&=~255;
4468 }
4469 ret |= jwin_numedit_proc(msg, d, c);
4470 break;
4471 case nswapHEX:
4472 d->d1 = 11; //11 digits max (incl '-', '.')
4473 if(msg==MSG_CHAR && !editproc_special_key(c))
4474 {
4475 if(!((c&255)=='.'||isxdigit(c&255)))
4476 c&=~255;
4477 else if(isxdigit(c&255) && !isdigit(c&255))
4478 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4479 {
4480 if(str[q] == '.') //No hex digits to the right of the '.'
4481 {
4482 c&=~255;
4483 break;
4484 }
4485 }
4486 if((c&255) && !areaselect)
4487 {
4488 int32_t p = 0;
4489 for(int32_t q = 0; str[q]; ++q)
4490 {
4491 if(str[q]=='.')
4492 {
4493 if((d->d2&0x0000FFFF) <= q)
4494 break; //typing before the '.'
4495 ++p;
4496 }
4497 else if(p) ++p;
4498 }
4499 if(p>=5) //too many chars after '.'
4500 c&=~255;
4501 }
4502 if(isalpha(c&255)) //always capitalize
4503 c = (c&~255) | (toupper(c&255));
4504 }
4505 ret |= jwin_hexedit_proc(msg, d, c);
4506 break;
4507 case nswapLDEC:
4508 d->d1 = 11; //11 digits max (incl '-')
4509 ret |= jwin_numedit_proc(msg, d, c);
4510 break;
4511 case nswapLHEX:
4512 d->d1 = 9; //9 digits max (incl '-')
4513 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4514 c = (c&~255) | (toupper(c&255));
4515 ret |= jwin_hexedit_proc(msg, d, c);
4516 break;
4517 }
4518 if(rev_d2 && ref_d2 == d->d2)
4519 {
4520 d->d2 = old_d2;
4521 }
4522
4523 if(msg==MSG_START)
4524 tf_obj->refresh_cb_swap();
4525
4526 return ret;
4527 }
4528
4529 /* _calc_scroll_bar:
4530 * Helps find positions of buttons on the scroll bar.
4531 */
4532 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4533 int32_t *bh, int32_t *len, int32_t *pos)
4534 {
4535 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4536 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4537 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4538 }
4539
4540 /* _handle_scrollable_click:
4541 * Helper to process a click on a scrollable object.
4542 */
4543
4544 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4545 {
4546 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4547
4548 int32_t xx, yy;
4549 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4550 int32_t hh = d->h - 32;
4551 int32_t obj = bar;
4552 int32_t bh, len, pos;
4553 int32_t down = 1, last_draw = 0;
4554 int32_t redraw = 0, mouse_delay = 0;
4555
4556 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4557
4558 xx = d->x + d->w - 18;
4559
4560 // find out which object is being clicked
4561
4562 yy = gui_mouse_y();
4563
4564 if(yy <= d->y+2+bh)
4565 {
4566 obj = top_btn;
4567 yy = d->y+2;
4568 }
4569 else if(yy >= d->y+d->h-2-bh)
4570 {
4571 obj = bottom_btn;
4572 yy = d->y+d->h-2-bh;
4573 }
4574 else if(d->h > 32+6)
4575 {
4576 if(yy < d->y+2+bh+pos)
4577 obj = top_bar;
4578 else if(yy >= d->y+2+bh+pos+len)
4579 obj = bottom_bar;
4580 }
4581
4582 while(gui_mouse_b())
4583 {
4584 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4585
4586 switch(obj)
4587 {
4588 case top_btn:
4589 case bottom_btn:
4590 down = mouse_in_rect(xx, yy, 16, bh);
4591
4592 if(!down)
4593 mouse_delay = 0;
4594 else
4595 {
4596 if((mouse_delay&1)==0)
4597 {
4598 if(obj==top_btn && *offset>0)
4599 {
4600 (*offset)--;
4601 redraw = 1;
4602 }
4603
4604 if(obj==bottom_btn && *offset<listsize-height)
4605 {
4606 (*offset)++;
4607 redraw = 1;
4608 }
4609 }
4610
4611 mouse_delay++;
4612 }
4613
4614 if(down!=last_draw || redraw)
4615 {
4616 vsync();
4617 d->proc(MSG_DRAW, d, 0);
4618 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4619 last_draw = down;
4620 }
4621
4622 break;
4623
4624 case top_bar:
4625 case bottom_bar:
4626 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4627 {
4628 if(obj==top_bar)
4629 {
4630 if(gui_mouse_y() < d->y+2+bh+pos)
4631 yy = *offset - height;
4632 }
4633 else
4634 {
4635 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4636 yy = *offset + height;
4637 }
4638
4639 if(yy < 0)
4640 yy = 0;
4641
4642 if(yy > listsize-height)
4643 yy = listsize-height;
4644
4645 if(yy != *offset)
4646 {
4647 *offset = yy;
4648 vsync();
4649 d->proc(MSG_DRAW, d, 0);
4650 }
4651 }
4652
4653 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4654
4655 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4656 break;
4657
4658 // fall through
4659
4660 case bar:
4661 default:
4662 xx = gui_mouse_y() - pos;
4663
4664 while(gui_mouse_b())
4665 {
4666 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4667
4668 if(yy > listsize-height)
4669 yy = listsize-height;
4670
4671 if(yy < 0)
4672 yy = 0;
4673
4674 bool should_redraw = false;
4675 if(yy != *offset)
4676 {
4677 *offset = yy;
4678 d->proc(MSG_DRAW, d, 0);
4679 should_redraw = true;
4680 }
4681
4682 /* let other objects continue to animate */
4683 int r = broadcast_dialog_message(MSG_IDLE, 0);
4684 if (r & D_REDRAWME) should_redraw = true;
4685
4686 if (should_redraw)
4687 {
4688 update_hw_screen();
4689 }
4690 }
4691
4692 break;
4693
4694 } // switch(obj)
4695
4696 redraw = 0;
4697
4698 update_hw_screen();
4699 // let other objects continue to animate
4700 broadcast_dialog_message(MSG_IDLE, 0);
4701 }
4702
4703 if(last_draw==1)
4704 {
4705 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4706 }
4707 }
4708
4709 /* _handle_scrollable_scroll:
4710 * Helper function to scroll through a scrollable object.
4711 */
4712
4713 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4714 {
4715 int32_t height = (d->h-3) / text_height(fnt);
4716
4717 if(listsize <= 0)
4718 {
4719 *index = *offset = 0;
4720 return;
4721 }
4722
4723 // check selected item
4724 if(*index < 0)
4725 *index = 0;
4726 else if(*index >= listsize)
4727 *index = listsize - 1;
4728
4729 // check scroll position
4730 while((*offset > 0) && (*offset + height > listsize))
4731 (*offset)--;
4732
4733 if(*offset >= *index)
4734 {
4735 if(*index < 0)
4736 *offset = 0;
4737 else
4738 *offset = *index;
4739 }
4740 else
4741 {
4742 while((*offset + height - 1) < *index)
4743 (*offset)++;
4744 }
4745 }
4746
4747 /* idle_cb:
4748 * rest_callback() routine to keep dialogs animating nice and smoothly.
4749 */
4750
4751 static void idle_cb()
4752 {
4753 broadcast_dialog_message(MSG_IDLE, 0);
4754 }
4755
4756 /* _handle_listbox_click:
4757 * Helper to process a click on a listbox, doing hit-testing and moving
4758 * the selection.
4759 */
4760
4761 static bool _handle_jwin_listbox_click(DIALOG *d)
4762 {
4763 ListData *data = (ListData *)d->dp;
4764 char *sel = (char *)d->dp2;
4765 int32_t listsize, height;
4766 int32_t i, j;
4767
4768 data->listFunc(-1, &listsize);
4769
4770 if(!listsize)
4771 return false;
4772
4773 height = (d->h-3) / text_height(*data->font);
4774
4775 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4776 ((d->h-3) / text_height(*data->font) - 1));
4777 i += d->d2;
4778
4779 if(i < d->d2)
4780 i = d->d2;
4781 else
4782 {
4783 if(i > d->d2 + height-1)
4784 i = d->d2 + height-1;
4785
4786 if(i >= listsize)
4787 i = listsize-1;
4788 }
4789
4790 if(gui_mouse_y() <= d->y)
4791 i = MAX(i-1, 0);
4792 else if(gui_mouse_y() >= d->y+d->h)
4793 i = MIN(i+1, listsize-1);
4794
4795 if(i != d->d1)
4796 {
4797 if(sel)
4798 {
4799 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG))
4800 {
4801 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4802 {
4803 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4804 sel[j] = TRUE;
4805 }
4806 else
4807 sel[i] = TRUE;
4808 }
4809 }
4810
4811 d->d1 = i;
4812 i = d->d2;
4813
4814 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4815
4816 object_message(d, MSG_DRAW, 0);
4817
4818 if(i != d->d2)
4819 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4820 return true;
4821 }
4822 return false;
4823 }
4824
4825 /* _jwin_draw_scrollable_frame:
4826 * Helper function to draw a frame for all objects with vertical scrollbars.
4827 */
4828 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4829 {
4830 int32_t pos, len;
4831 int32_t xx, yy, hh, bh;
4832 static BITMAP *pattern = NULL; // just create it once
4833
4834 /* draw frame */
4835 if(type)
4836 // for droplists
4837 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4838 else
4839 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4840
4841 /* possibly draw scrollbar */
4842 if(listsize > height)
4843 {
4844 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4845
4846 xx = d->x + d->w - 18;
4847
4848 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4849 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4850
4851 if(d->h > 32)
4852 {
4853 yy = d->y + 16;
4854 hh = (d->h-32);
4855
4856 /* create and draw the scrollbar */
4857 if(!pattern)
4858 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4859
4860 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4861 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4862 putpixel(pattern, 0, 0, scheme[jcBOX]);
4863 putpixel(pattern, 1, 1, scheme[jcBOX]);
4864
4865 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4866 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4867 solid_mode();
4868
4869 if(d->h > 32+6)
4870 {
4871 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4872 }
4873 }
4874
4875 if(d->flags & D_GOTFOCUS)
4876 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4877 }
4878 else if(d->flags & D_GOTFOCUS)
4879 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4880 }
4881
4882 /*
4883 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4884 */
4885 void _jwin_draw_abclistbox(DIALOG *d)
4886 {
4887 int32_t height, listsize, i, len, bar, x, y, w;
4888 int32_t fg_color, bg_color, fg, bg;
4889 char *sel = (char*)d->dp2;
4890 char s[1024] = { 0 };
4891 ListData *data = (ListData *)d->dp;
4892
4893 FONT* oldfont = font;
4894 font = *data->font;
4895
4896 data->listFunc(-1, &listsize);
4897 height = (d->h-3) / text_height(font);
4898 bar = (listsize > height);
4899 w = (bar ? d->w-21 : d->w-5);
4900 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4901 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4902 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4903
4904 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4905 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4906 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4907 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4908 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4909 {
4910 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4911 strncpy(s, abc_keypresses, 1023);
4912 char* s2 = s;
4913 int32_t tw = (d->w-1);
4914 while(text_length(font, s2) >= tw)
4915 {
4916 ++s2;
4917 }
4918 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4919 }
4920 //d->flags|=D_DIRTY;
4921
4922 /* draw box contents */
4923 for(i=0; i<height; i++)
4924 {
4925 if(d->d2+i < listsize)
4926 {
4927 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4928 {
4929 fg = scheme[jcSELFG];
4930 bg = scheme[jcSELBG];
4931 }
4932 else if((sel) && (sel[d->d2+i]))
4933 {
4934 fg = scheme[jcDISABLED_FG];
4935 bg = scheme[jcSELBG];
4936 }
4937 else
4938 {
4939 fg = fg_color;
4940 bg = bg_color;
4941 }
4942
4943 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4944 x = d->x + 4;
4945 y = d->y + 4 + i*text_height(*data->font);
4946 // text_mode(bg);
4947 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4948 x += 8;
4949 len = (int32_t)strlen(s);
4950
4951 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4952 {
4953 len--;
4954 s[len] = 0;
4955 }
4956
4957 textout_ex(screen, *data->font, s, x, y, fg,bg);
4958 x += text_length(*data->font, s);
4959
4960 if(x <= d->x+w)
4961 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4962 }
4963 else
4964 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4965 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4966 }
4967
4968 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4969 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4970 d->x+w+2, d->y+d->h-3, bg_color);
4971
4972 /* draw frame, maybe with scrollbar */
4973 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4974
4975 font = oldfont;
4976 }
4977
4978 /* _jwin_draw_listbox:
4979 * Helper function to draw a listbox object.
4980 */
4981 void _jwin_draw_listbox(DIALOG *d)
4982 {
4983 int32_t height, listsize, i, len, bar, x, y, w;
4984 int32_t fg_color, bg_color, fg, bg;
4985 char *sel = (char*)d->dp2;
4986 char s[1024] = {0};
4987 ListData *data = (ListData *)d->dp;
4988
4989 data->listFunc(-1, &listsize);
4990 height = (d->h-3) / text_height(*data->font);
4991 bar = (listsize > height);
4992 w = (bar ? d->w-21 : d->w-5);
4993 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4994 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4995
4996 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4997 vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4998 vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4999 vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
5000 vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
5001
5002 /* draw box contents */
5003 for(i=0; i<height; i++)
5004 {
5005 if(d->d2+i < listsize)
5006 {
5007 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
5008 {
5009 fg = scheme[jcSELFG];
5010 bg = scheme[jcSELBG];
5011 }
5012 else if((sel) && (sel[d->d2+i]))
5013 {
5014 fg = scheme[jcMEDDARK];
5015 bg = scheme[jcSELBG];
5016 }
5017 else
5018 {
5019 fg = fg_color;
5020 bg = bg_color;
5021 }
5022
5023 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
5024 x = d->x + 4;
5025 y = d->y + 4 + i*text_height(*data->font);
5026 // text_mode(bg);
5027 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
5028 x += 8;
5029 len = (int32_t)strlen(s);
5030
5031 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
5032 {
5033 len--;
5034 s[len] = 0;
5035 }
5036
5037 textout_ex(screen, *data->font, s, x, y, fg,bg);
5038 x += text_length(*data->font, s);
5039
5040 if(x <= d->x+w)
5041 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
5042 }
5043 else
5044 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5045 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
5046 }
5047
5048 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
5049 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
5050 d->x+w+2, d->y+d->h-3, bg_color);
5051
5052 /* draw frame, maybe with scrollbar */
5053 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
5054 }
5055
5056 /* jwin_list_proc:
5057 * A list box object. The dp field points to a ListData struct containing
5058 * a function which it will call
5059 * to obtain information about the list. This should follow the form:
5060 * char *<list_func_name> (int32_t index, int32_t *list_size);
5061 * If index is zero or positive, the function should return a pointer to
5062 * the string which is to be displayed at position index in the list. If
5063 * index is negative, it should return null and list_size should be set
5064 * to the number of items in the list. The list box object will allow the
5065 * user to scroll through the list and to select items list by clicking
5066 * on them, and if it has the input focus also by using the arrow keys. If
5067 * the D_EXIT flag is set, double clicking on a list item will cause it to
5068 * close the dialog. The index of the selected item is held in the d1
5069 * field, and d2 is used to store how far it has scrolled through the list.
5070 */
5071 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
5072 {
5073 ListData *data = (ListData *)d->dp;
5074 int32_t listsize, i, bottom, height, bar, orig;
5075 char *sel = (char *)d->dp2;
5076 int32_t redraw = FALSE;
5077
5078 switch(msg)
5079 {
5080
5081 case MSG_START:
5082 data->listFunc(-1, &listsize);
5083 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5084 break;
5085
5086 case MSG_DRAW:
5087 _jwin_draw_listbox(d);
5088 break;
5089
5090 case MSG_CLICK:
5091 data->listFunc(-1, &listsize);
5092 height = (d->h-3) / text_height(*data->font);
5093 bar = (listsize > height);
5094
5095 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5096 {
5097 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5098 {
5099 for(i=0; i<listsize; i++)
5100 {
5101 if(sel[i])
5102 {
5103 redraw = TRUE;
5104 sel[i] = FALSE;
5105 }
5106 }
5107
5108 if(redraw)
5109 {
5110 object_message(d, MSG_DRAW, 0);
5111 }
5112 }
5113
5114 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5115
5116 bool rightClicked=(gui_mouse_b()&2)!=0;
5117 while(gui_mouse_b())
5118 {
5119 broadcast_dialog_message(MSG_IDLE, 0);
5120 d->flags |= D_INTERNAL;
5121 bool should_redraw = false;
5122 if(_handle_jwin_listbox_click(d))
5123 {
5124 d->flags &= ~D_INTERNAL;
5125 GUI_EVENT(d, geCHANGE_SELECTION);
5126 should_redraw = true;
5127 }
5128 d->flags &= ~D_INTERNAL;
5129
5130 /* let other objects continue to animate */
5131 int r = broadcast_dialog_message(MSG_IDLE, 0);
5132 if (r & D_REDRAWME) should_redraw = true;
5133
5134 if (should_redraw)
5135 {
5136 update_hw_screen();
5137 }
5138 }
5139
5140 if(rightClicked)
5141 {
5142 GUI_EVENT(d, geRCLICK);
5143 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5144 {
5145 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5146 funcType func=reinterpret_cast<funcType>(d->dp3);
5147 func(d->d1, gui_mouse_x(), gui_mouse_y());
5148 }
5149 }
5150
5151 if(d->flags & D_USER)
5152 {
5153 if(listsize)
5154 {
5155 clear_keybuf();
5156 return D_CLOSE;
5157 }
5158 }
5159
5160 return D_REDRAWME;
5161 }
5162 else
5163 {
5164 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5165 }
5166
5167 break;
5168
5169 case MSG_DCLICK:
5170 // Ignore double right-click
5171 if((gui_mouse_b()&2)!=0)
5172 break;
5173
5174 data->listFunc(-1, &listsize);
5175 height = (d->h-3) / text_height(*data->font);
5176 bar = (listsize > height);
5177
5178 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5179 {
5180 if(listsize)
5181 {
5182 i = d->d1;
5183 object_message(d, MSG_CLICK, 0);
5184
5185 if(i == d->d1)
5186 {
5187 if(d->flags & D_EXIT)
5188 return D_CLOSE;
5189 else GUI_EVENT(d, geDCLICK);
5190 }
5191 }
5192 }
5193
5194 break;
5195
5196 case MSG_KEY:
5197 data->listFunc(-1, &listsize);
5198
5199 if((listsize) && (d->flags & D_EXIT))
5200 return D_CLOSE;
5201
5202 break;
5203
5204 case MSG_WANTFOCUS:
5205 return D_WANTFOCUS;
5206
5207 case MSG_WANTWHEEL:
5208 return 1;
5209
5210 case MSG_WHEEL:
5211 data->listFunc(-1, &listsize);
5212 height = (d->h-4) / text_height(*data->font);
5213
5214 if(height < listsize)
5215 {
5216 int32_t delta = (height > 3) ? 3 : 1;
5217
5218 if(c > 0)
5219 {
5220 i = MAX(0, d->d2-delta);
5221 }
5222 else
5223 {
5224 i = MIN(listsize-height, d->d2+delta);
5225 }
5226
5227 if(i != d->d2)
5228 {
5229 d->d2 = i;
5230 object_message(d, MSG_DRAW, 0);
5231 GUI_EVENT(d, geCHANGE_SELECTION);
5232 return D_REDRAWME;
5233 }
5234 }
5235
5236 break;
5237
5238 case MSG_CHAR:
5239 data->listFunc(-1,&listsize);
5240
5241 if(listsize)
5242 {
5243 c >>= 8;
5244
5245 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5246
5247 if(bottom >= listsize-1)
5248 bottom = listsize-1;
5249
5250 orig = d->d1;
5251
5252 if(c == KEY_UP)
5253 d->d1--;
5254 else if(c == KEY_DOWN)
5255 d->d1++;
5256 else if(c == KEY_HOME)
5257 d->d1 = 0;
5258 else if(c == KEY_END)
5259 d->d1 = listsize-1;
5260 else if(c == KEY_PGUP)
5261 {
5262 if(d->d1 > d->d2)
5263 d->d1 = d->d2;
5264 else
5265 d->d1 -= (bottom - d->d2);
5266 }
5267 else if(c == KEY_PGDN)
5268 {
5269 if(d->d1 < bottom)
5270 d->d1 = bottom;
5271 else
5272 d->d1 += (bottom - d->d2);
5273 }
5274 else
5275 return D_O_K;
5276
5277 if(sel)
5278 {
5279 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5280 {
5281 for(i=0; i<listsize; i++)
5282 sel[i] = FALSE;
5283 }
5284 else if(key_shifts & KB_SHIFT_FLAG)
5285 {
5286 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5287 {
5288 if(key_shifts & KB_CTRL_CMD_FLAG)
5289 sel[i] = (i != d->d1);
5290 else
5291 sel[i] = TRUE;
5292 }
5293 }
5294 }
5295
5296 /* if we changed something, better redraw... !Also bounds the index! */
5297 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5298
5299 GUI_EVENT(d, geCHANGE_SELECTION);
5300
5301 if (d->d1 != orig)
5302 d->flags |= D_DIRTY;
5303 return D_USED_CHAR;
5304 }
5305
5306 break;
5307 }
5308
5309 return D_O_K;
5310 }
5311
5312
5313 /*
5314 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5315 This calls the appropriate form of drawing for those listers.
5316 */
5317 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5318 {
5319 ListData *data = (ListData *)d->dp;
5320 int32_t listsize, i, bottom, height, bar, orig, h;
5321 int32_t ret = D_O_K;
5322 bool revert_size = false;
5323 if((d->flags & D_RESIZED) == 0)
5324 {
5325 h = d->h;
5326 d->h -= text_height(*data->font);
5327 d->flags |= D_RESIZED;
5328 revert_size = true;
5329 }
5330 char *sel = (char *)d->dp2;
5331 int32_t redraw = FALSE;
5332
5333 switch(msg)
5334 {
5335
5336 case MSG_START:
5337 data->listFunc(-1, &listsize);
5338 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5339 break;
5340
5341 case MSG_DRAW:
5342 _jwin_draw_abclistbox(d);
5343 break;
5344
5345 case MSG_CLICK:
5346 if(gui_mouse_y() > (d->y+d->h-1))
5347 {
5348 if(gui_mouse_y() > (d->y+d->h+2))
5349 {
5350 //Clicked on the box displaying the patternmatch
5351 }
5352 else {} //Clicked between the lister and patternmatch
5353 }
5354 else //Clicked the lister
5355 {
5356 data->listFunc(-1, &listsize);
5357 height = (d->h-3) / text_height(*data->font);
5358 bar = (listsize > height);
5359
5360 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5361 {
5362 if((sel) && (!(key_shifts & KB_CTRL_CMD_FLAG)))
5363 {
5364 for(i=0; i<listsize; i++)
5365 {
5366 if(sel[i])
5367 {
5368 redraw = TRUE;
5369 sel[i] = FALSE;
5370 }
5371 }
5372
5373 if(redraw)
5374 {
5375 object_message(d, MSG_DRAW, 0);
5376 }
5377 }
5378
5379 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5380
5381 bool rightClicked=(gui_mouse_b()&2)!=0;
5382 while(gui_mouse_b())
5383 {
5384 broadcast_dialog_message(MSG_IDLE, 0);
5385 d->flags |= D_INTERNAL;
5386 if(_handle_jwin_listbox_click(d))
5387 {
5388 d->flags &= ~D_INTERNAL;
5389 GUI_EVENT(d, geCHANGE_SELECTION);
5390 update_hw_screen();
5391 }
5392 d->flags &= ~D_INTERNAL;
5393 rest(1);
5394 }
5395
5396 if(rightClicked)
5397 {
5398 GUI_EVENT(d, geRCLICK);
5399 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5400 {
5401 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5402 funcType func=reinterpret_cast<funcType>(d->dp3);
5403 func(d->d1, gui_mouse_x(), gui_mouse_y());
5404 }
5405 }
5406
5407 if(d->flags & D_USER)
5408 {
5409 if(listsize)
5410 {
5411 clear_keybuf();
5412 ret = D_CLOSE;
5413 }
5414 }
5415
5416 return D_REDRAWME;
5417 }
5418 else
5419 {
5420 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5421 }
5422 }
5423 break;
5424
5425 case MSG_DCLICK:
5426 // Ignore double right-click
5427 if((gui_mouse_b()&2)!=0)
5428 break;
5429
5430 if(gui_mouse_y() > (d->y+d->h-1))
5431 {
5432 if(gui_mouse_y() > (d->y+d->h+2))
5433 {
5434 //Clicked on the box displaying the patternmatch
5435 }
5436 else {} //Clicked between the lister and patternmatch
5437 }
5438 else //Clicked the lister
5439 {
5440 data->listFunc(-1, &listsize);
5441 height = (d->h-3) / text_height(*data->font);
5442 bar = (listsize > height);
5443
5444 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5445 {
5446 if(listsize)
5447 {
5448 i = d->d1;
5449 object_message(d, MSG_CLICK, 0);
5450
5451 if(i == d->d1)
5452 {
5453 if(d->flags & D_EXIT)
5454 ret = D_CLOSE;
5455 else GUI_EVENT(d, geDCLICK);
5456 }
5457 }
5458 }
5459 }
5460 break;
5461
5462 case MSG_KEY:
5463 data->listFunc(-1, &listsize);
5464
5465 if((listsize) && (d->flags & D_EXIT))
5466 ret = D_CLOSE;
5467
5468 break;
5469
5470 case MSG_WANTFOCUS:
5471 ret = D_WANTFOCUS;
5472 break;
5473
5474 case MSG_WANTWHEEL:
5475 return 1;
5476
5477 case MSG_WHEEL:
5478 data->listFunc(-1, &listsize);
5479 height = (d->h-4) / text_height(*data->font);
5480
5481 if(height < listsize)
5482 {
5483 int32_t delta = (height > 3) ? 3 : 1;
5484
5485 if(c > 0)
5486 {
5487 i = MAX(0, d->d2-delta);
5488 }
5489 else
5490 {
5491 i = MIN(listsize-height, d->d2+delta);
5492 }
5493
5494 if(i != d->d2)
5495 {
5496 d->d2 = i;
5497 object_message(d, MSG_DRAW, 0);
5498 GUI_EVENT(d, geCHANGE_SELECTION);
5499 ret |= D_REDRAWME;
5500 }
5501 }
5502
5503 break;
5504
5505 case MSG_CHAR:
5506 data->listFunc(-1,&listsize);
5507
5508 if(listsize)
5509 {
5510 c >>= 8;
5511
5512 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5513
5514 if(bottom >= listsize-1)
5515 bottom = listsize-1;
5516
5517 orig = d->d1;
5518
5519 if(c == KEY_UP)
5520 d->d1--;
5521 else if(c == KEY_DOWN)
5522 d->d1++;
5523 else if(c == KEY_HOME)
5524 d->d1 = 0;
5525 else if(c == KEY_END)
5526 d->d1 = listsize-1;
5527 else if(c == KEY_PGUP)
5528 {
5529 if(d->d1 > d->d2)
5530 d->d1 = d->d2;
5531 else
5532 d->d1 -= (bottom - d->d2);
5533 }
5534 else if(c == KEY_PGDN)
5535 {
5536 if(d->d1 < bottom)
5537 d->d1 = bottom;
5538 else
5539 d->d1 += (bottom - d->d2);
5540 }
5541 else
5542 break; //return D_O_K;
5543
5544 if(sel)
5545 {
5546 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_CMD_FLAG)))
5547 {
5548 for(i=0; i<listsize; i++)
5549 sel[i] = FALSE;
5550 }
5551 else if(key_shifts & KB_SHIFT_FLAG)
5552 {
5553 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5554 {
5555 if(key_shifts & KB_CTRL_CMD_FLAG)
5556 sel[i] = (i != d->d1);
5557 else
5558 sel[i] = TRUE;
5559 }
5560 }
5561 }
5562
5563 /* if we changed something, better redraw... */
5564 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5565
5566 GUI_EVENT(d, geCHANGE_SELECTION);
5567
5568 if (d->d1 != orig)
5569 d->flags |= D_DIRTY;
5570 ret = D_USED_CHAR;
5571 }
5572
5573 break;
5574 }
5575 if(revert_size)
5576 {
5577 d->h = h;
5578 d->flags &= ~D_RESIZED;
5579 }
5580 return ret;
5581 }
5582
5583 /* _jwin_draw_textbox:
5584 * Helper function to draw a textbox object.
5585 */
5586 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5587 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5588 int32_t disabled)
5589 {
5590 int32_t fg = scheme[jcTEXTFG];
5591 int32_t bg = scheme[jcTEXTBG];
5592 int32_t y1 = y+4;
5593 int32_t x1;
5594 int32_t len;
5595 int32_t ww = w-10;
5596 char s[16] = {0};
5597 char text[16] = {0};
5598 char space[16] = {0};
5599 char *printed = text;
5600 char *scanned = text;
5601 char *oldscan = text;
5602 char *ignore = NULL;
5603 char *tmp, *ptmp;
5604 int32_t width;
5605 int32_t line = 0;
5606 int32_t i = 0;
5607 int32_t noignore;
5608 // int32_t rtm;
5609
5610 usetc(s+usetc(s, '.'), 0);
5611 usetc(text+usetc(text, ' '), 0);
5612 usetc(space+usetc(space, ' '), 0);
5613
5614 /* find the correct text */
5615 if(thetext != NULL)
5616 {
5617 printed = thetext;
5618 scanned = thetext;
5619 }
5620
5621 /* choose the text color */
5622 if(disabled)
5623 {
5624 fg = scheme[jcDISABLED_FG];
5625 bg = scheme[jcDISABLED_BG];
5626 }
5627
5628 /* do some drawing setup */
5629 if(draw)
5630 {
5631 /* initial start blanking at the top */
5632 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5633 }
5634
5635 // rtm = text_mode(bg);
5636
5637 /* loop over the entire string */
5638 for(;;)
5639 {
5640 width = 0;
5641
5642 /* find the next break */
5643 while(ugetc(scanned))
5644 {
5645 /* check for a forced break */
5646 if(ugetc(scanned) == '\n')
5647 {
5648 scanned += uwidth(scanned);
5649
5650 /* we are done parsing the line end */
5651 break;
5652 }
5653
5654 /* the next character length */
5655 usetc(s+usetc(s, ugetc(scanned)), 0);
5656 len = text_length(font, s);
5657
5658 /* modify length if its a tab */
5659 if(ugetc(s) == '\t')
5660 len = tabsize * text_length(font, space);
5661
5662 /* check for the end of a line by excess width of next char */
5663 if(width+len >= ww)
5664 {
5665 /* we have reached end of line do we go back to find start */
5666 if(wword)
5667 {
5668 /* remember where we were */
5669 oldscan = scanned;
5670 noignore = FALSE;
5671
5672 /* go backwards looking for start of word */
5673 while(!uisspace(ugetc(scanned)))
5674 {
5675 /* don't wrap too far */
5676 if(scanned == printed)
5677 {
5678 /* the whole line is filled, so stop here */
5679 tmp = ptmp = scanned;
5680
5681 while(ptmp != oldscan)
5682 {
5683 ptmp = tmp;
5684 tmp += uwidth(tmp);
5685 }
5686
5687 scanned = ptmp;
5688 noignore = TRUE;
5689 break;
5690 }
5691
5692 /* look further backwards to wrap */
5693 tmp = ptmp = printed;
5694
5695 while(tmp < scanned)
5696 {
5697 ptmp = tmp;
5698 tmp += uwidth(tmp);
5699 }
5700
5701 scanned = ptmp;
5702 }
5703
5704 /* put the space at the end of the line */
5705 if(!noignore)
5706 {
5707 ignore = scanned;
5708 scanned += uwidth(scanned);
5709 }
5710 else
5711 ignore = NULL;
5712
5713 /* check for endline at the convenient place */
5714 if(ugetc(scanned) == '\n')
5715 scanned += uwidth(scanned);
5716 }
5717
5718 /* we are done parsing the line end */
5719 break;
5720 }
5721
5722 /* the character can be added */
5723 scanned += uwidth(scanned);
5724 width += len;
5725 }
5726
5727 /* check if we are to print it */
5728 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5729 {
5730 x1 = x+4;
5731
5732 /* the initial blank bit */
5733 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5734
5735 /* print up to the marked character */
5736 while(printed != scanned)
5737 {
5738 /* do special stuff for each character */
5739 switch(ugetc(printed))
5740 {
5741
5742 case '\r':
5743 case '\n':
5744 /* don't print endlines in the text */
5745 break;
5746
5747 /* possibly expand the tabs */
5748 case '\t':
5749 for(i=0; i<tabsize; i++)
5750 {
5751 usetc(s+usetc(s, ' '), 0);
5752 textout_ex(screen, font, s, x1, y1, fg,bg);
5753 x1 += text_length(font, s);
5754 }
5755
5756 break;
5757
5758 /* print a normal character */
5759 default:
5760 if(printed != ignore)
5761 {
5762 usetc(s+usetc(s, ugetc(printed)), 0);
5763 textout_ex(screen, font, s, x1, y1, fg,bg);
5764 x1 += text_length(font, s);
5765 }
5766 }
5767
5768 /* goto the next character */
5769 printed += uwidth(printed);
5770 }
5771
5772 /* the last blank bit */
5773 if(x1 <= x+w-3)
5774 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5775
5776 /* print the line end */
5777 y1 += text_height(font);
5778 }
5779
5780 printed = scanned;
5781
5782 /* we have done a line */
5783 line++;
5784
5785 /* check if we are at the end of the string */
5786 if(!ugetc(printed))
5787 {
5788 /* the under blank bit */
5789 if(draw)
5790 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5791
5792 /* tell how many lines we found */
5793 *listsize = line;
5794 // text_mode(rtm);
5795 return;
5796 }
5797 }
5798
5799 // text_mode(rtm);
5800 }
5801
5802 /* jwin_textbox_proc:
5803 * A text box object. The dp field points to a char * which is the text
5804 * to be displayed in the text box. If the text is long, there will be
5805 * a vertical scrollbar on the right hand side of the object which can
5806 * be used to scroll through the text. The default is to print the text
5807 * with word wrapping, but if the D_SELECTED flag is set, the text will
5808 * be printed with character wrapping. The d1 field is used internally
5809 * to store the number of lines of text, and d2 is used to store how far
5810 * it has scrolled through the text.
5811 */
5812 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5813 {
5814 int32_t height, bar, ret = D_O_K;
5815 int32_t start, top, bottom,l;
5816 int32_t used, delta;
5817 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5818
5819 FONT *oldfont=NULL;
5820
5821 if(d->dp2!=NULL)
5822 {
5823 oldfont=font;
5824 font=(FONT*)d->dp2;
5825 }
5826
5827 /* calculate the actual height */
5828 height = (d->h-4) / text_height(font);
5829
5830 switch(msg)
5831 {
5832
5833 case MSG_START:
5834 /* measure how many lines of text we contain */
5835 _jwin_draw_textbox((char*)d->dp, &d->d1,
5836 0, /* DONT DRAW anything */
5837 d->d2, !(d->flags & D_SELECTED), 8,
5838 d->x, d->y, d->w, d->h,
5839 (d->flags & D_DISABLED));
5840 break;
5841
5842 case MSG_DRAW:
5843 /* tell the object to sort of draw, but only calculate the listsize */
5844 _jwin_draw_textbox((char*)d->dp, &d->d1,
5845 0, /* DONT DRAW anything */
5846 d->d2, !(d->flags & D_SELECTED), 8,
5847 d->x, d->y, d->w, d->h,
5848 (d->flags & D_DISABLED));
5849
5850 if(d->d1 > height)
5851 {
5852 bar = 16;
5853 }
5854 else
5855 {
5856 bar = 0;
5857 d->d2 = 0;
5858 }
5859
5860 /* now do the actual drawing */
5861 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5862 !(d->flags & D_SELECTED), 8,
5863 d->x, d->y, d->w-bar-1, d->h,
5864 (d->flags & D_DISABLED));
5865
5866 /* draw the frame around */
5867 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5868 break;
5869
5870 case MSG_CLICK:
5871 /* figure out if it's on the text or the scrollbar */
5872 bar = (d->d1 > height);
5873
5874 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5875 {
5876 /* clicked on the text area */
5877 ret = D_O_K;
5878 }
5879 else
5880 {
5881 /* clicked on the scroll area */
5882 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5883 }
5884
5885 break;
5886
5887 case MSG_WANTWHEEL:
5888 return 1;
5889
5890 case MSG_WHEEL:
5891 l = (d->h-8)/text_height(font);
5892 delta = (l > 3) ? 3 : 1;
5893
5894 // scroll, making sure that the list stays in bounds
5895 start = d->d2;
5896 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5897
5898 // if we changed something, better redraw...
5899 if(d->d2 != start)
5900 {
5901 d->flags |= D_DIRTY;
5902 }
5903
5904 ret = D_O_K;
5905 break;
5906
5907 case MSG_CHAR:
5908 start = d->d2;
5909 used = D_USED_CHAR;
5910
5911 if(d->d1 > 0)
5912 {
5913 if(d->d2 > 0)
5914 top = d->d2+1;
5915 else
5916 top = 0;
5917
5918 l = (d->h-3)/text_height(font);
5919
5920 bottom = d->d2 + l - 1;
5921
5922 if(bottom >= d->d1-1)
5923 bottom = d->d1-1;
5924 else
5925 bottom--;
5926
5927 if((c>>8) == KEY_UP)
5928 d->d2--;
5929 else if((c>>8) == KEY_DOWN)
5930 d->d2++;
5931 else if((c>>8) == KEY_HOME)
5932 d->d2 = 0;
5933 else if((c>>8) == KEY_END)
5934 d->d2 = d->d1-l;
5935 else if((c>>8) == KEY_PGUP)
5936 d->d2 = d->d2-(bottom-top);
5937 else if((c>>8) == KEY_PGDN)
5938 d->d2 = d->d2+(bottom-top);
5939 else
5940 used = D_O_K;
5941
5942 /* make sure that the list stays in bounds */
5943 if(d->d2 > d->d1-l)
5944 d->d2 = d->d1-l;
5945
5946 if(d->d2 < 0)
5947 d->d2 = 0;
5948 }
5949 else
5950 used = D_O_K;
5951
5952 /* if we changed something, better redraw... */
5953 if(d->d2 != start)
5954 {
5955 d->proc(MSG_DRAW, d, 0);
5956 }
5957
5958 ret = used;
5959 break;
5960
5961 case MSG_WANTFOCUS:
5962
5963 /* if we don't have a scrollbar we can't do anything with the focus */
5964 if(d->d1 > height)
5965 ret = D_WANTFOCUS;
5966
5967 break;
5968
5969 default:
5970 ret = D_O_K;
5971 }
5972
5973 if(d->dp2!=NULL)
5974 {
5975 font=oldfont;
5976 }
5977
5978 return ret;
5979 }
5980
5981 /* jwin_slider_proc:
5982 * A slider control object. This object returns a value in d2, in the
5983 * range from 0 to d1. It will display as a vertical slider if h is
5984 * greater than or equal to w; otherwise, it will display as a horizontal
5985 * slider. dp can contain an optional bitmap to use for the slider handle;
5986 * dp2 can contain an optional callback function, which is called each
5987 * time d2 changes. The callback function should have the following
5988 * prototype:
5989 *
5990 * int32_t function(void *dp3, int32_t d2);
5991 *
5992 * The d_slider_proc object will return the value of the callback function.
5993 */
5994 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
5995 {
5996 BITMAP *slhan = NULL;
5997 int32_t sfg; /* slider foreground color */
5998 int32_t vert = TRUE; /* flag: is slider vertical? */
5999 int32_t hh = 7; /* handle height (width for horizontal sliders) */
6000 int32_t hmar; /* handle margin */
6001 int32_t slp; /* slider position */
6002 int32_t irange;
6003 int32_t slx, sly, slh, slw;
6004 fixed slratio, slmax, slpos;
6005 ASSERT(d);
6006
6007 /* check for slider direction */
6008 if(d->h < d->w)
6009 {
6010 vert = FALSE;
6011 }
6012
6013 /* set up the metrics for the control */
6014 if(d->dp != NULL)
6015 {
6016 slhan = (BITMAP *)d->dp;
6017
6018 if(vert)
6019 {
6020 hh = slhan->h;
6021 }
6022 else
6023 {
6024 hh = slhan->w;
6025 }
6026 }
6027
6028 hmar = hh/2;
6029 irange = (vert) ? d->h : d->w;
6030 slmax = itofix(irange-hh);
6031 slratio = slmax / (d->d1);
6032 slpos = slratio * d->d2;
6033 slp = fixtoi(slpos);
6034
6035 switch(msg)
6036 {
6037 case MSG_DRAW:
6038 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6039 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
6040
6041 if(vert)
6042 {
6043 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
6044 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
6045 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6046 }
6047 else
6048 {
6049 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
6050 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
6051 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
6052 }
6053
6054 if(d->flags & D_GOTFOCUS)
6055 {
6056 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
6057 }
6058
6059 /* okay, background and slot are drawn, now draw the handle */
6060 if(slhan)
6061 {
6062 if(vert)
6063 {
6064 slx = d->x+(d->w/2)-(slhan->w/2);
6065 sly = d->y+d->h-(hh+slp);
6066 }
6067 else
6068 {
6069 slx = d->x+slp;
6070 sly = d->y+(d->h/2)-(slhan->h/2);
6071 }
6072
6073 draw_sprite(screen, slhan, slx, sly);
6074 }
6075 else
6076 {
6077 /* draw default handle */
6078 if(vert)
6079 {
6080 slx = d->x;
6081 sly = d->y+d->h-(hh+slp);
6082 slw = d->w;
6083 slh = hh;
6084 }
6085 else
6086 {
6087 slx = d->x+slp;
6088 sly = d->y;
6089 slw = hh;
6090 slh = d->h;
6091 }
6092
6093 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6094 }
6095
6096 break;
6097
6098 default:
6099 return d_jslider_proc(msg, d, c);
6100 }
6101
6102 return D_O_K;
6103 }
6104
6105 const char* rowpref(int32_t row, bool alt)
6106 {
6107 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6108 switch(row)
6109 {
6110 case 2: case 3: case 4: case 9:
6111 return lcol;
6112 case 14:
6113 return alt ? syscol : bosscol;
6114 case 15:
6115 return thmcol;
6116 default:
6117 return nlcol;
6118 }
6119 }
6120
6121 byte getHighlightColor(int32_t c)
6122 {
6123 RGB col;
6124 get_color(c, &col);
6125 return getHighlightColor(col);
6126 }
6127
6128 byte getHighlightColor(RGB const& col)
6129 {
6130 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6131 (pow(col.g/64.0, 2.2) * 0.7152) +
6132 (pow(col.b/64.0, 2.2) * 0.0722);
6133 return lum < 0.4 ? vc(15) : vc(0);
6134 //Old -Em
6135 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6136 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6137 // byte highlightColor = vc(7); //sysgray
6138 // if(bright >= 2)
6139 // {
6140 // if(sbright >= 2)
6141 // highlightColor = vc(0); //sysblack
6142 // else highlightColor = vc(8); //sysdarkgray
6143 // }
6144 // else if(!bright)
6145 // highlightColor = vc(15); //syswhite
6146 // return highlightColor;
6147 }
6148
6149 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6150 {
6151 int32_t ret = D_O_K;
6152 if(!d->d2) d->d2 = 12;
6153 bool alt = d->d2 > 16;
6154 int32_t numcsets = alt ? 16 : d->d2;
6155 int32_t numcol = numcsets*0x10;
6156 if(msg==MSG_START)
6157 {
6158 d->w = d->h = (16*8) * 1.5;
6159 }
6160 int32_t csz = 12;
6161 d->w = csz * 16;
6162 d->h = csz * numcsets;
6163 switch(msg)
6164 {
6165 case MSG_DRAW:
6166 {
6167 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6168 for(int32_t c = 0; c < numcol; ++c)
6169 {
6170 int32_t x = (c%16)*csz, y = (c/16)*csz;
6171 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6172 if(c == d->d1)
6173 {
6174 byte highlightColor = getHighlightColor(c);
6175 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6176 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6177 }
6178 }
6179
6180 FONT *oldfont = font;
6181
6182 if(d->dp2)
6183 {
6184 font = (FONT*)d->dp2;
6185 }
6186
6187 char buf[32]={0};
6188 for(int32_t col = 0; col < 16; ++col)
6189 {
6190 sprintf(buf, "%X", col);
6191 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6192 }
6193 for(int32_t row = 0; row < numcsets; ++row)
6194 {
6195 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6196 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6197 }
6198
6199 font = oldfont;
6200 break;
6201 }
6202
6203 case MSG_CLICK:
6204 {
6205 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6206 {
6207 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6208
6209 if(col>-1 && col != d->d1)
6210 {
6211 d->d1 = col;
6212 ret |= D_REDRAWME;
6213 }
6214 ret |= D_WANTFOCUS;
6215 }
6216 break;
6217 }
6218
6219 case MSG_WANTFOCUS:
6220 case MSG_LOSTFOCUS:
6221 case MSG_KEY:
6222 ret = D_WANTFOCUS;
6223 break;
6224
6225 case MSG_CHAR:
6226 {
6227 ret = D_USED_CHAR | D_REDRAWME;
6228 switch(c>>8)
6229 {
6230 case KEY_LEFT:
6231 {
6232 if(d->d1 % 0x10)
6233 --d->d1;
6234 break;
6235 }
6236 case KEY_RIGHT:
6237 {
6238 if(d->d1 % 0x10 != 0x0F)
6239 ++d->d1;
6240 break;
6241 }
6242 case KEY_UP:
6243 {
6244 if(d->d1 / 0x10)
6245 d->d1 -= 0x10;
6246 break;
6247 }
6248 case KEY_DOWN:
6249 {
6250 if(d->d1 / 0x10 != numcsets)
6251 d->d1 += 0x10;
6252 break;
6253 }
6254 case KEY_ENTER:
6255 {
6256 ret = D_CLOSE;
6257 break;
6258 }
6259 default: ret = D_O_K;
6260 }
6261 break;
6262 }
6263 }
6264 return ret;
6265 }
6266
6267 static DIALOG selcolor_dlg[] =
6268 {
6269 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6270 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6271 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6272 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6273
6274 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6275 };
6276
6277 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6278 {
6279 int32_t ret = D_O_K;
6280
6281 switch(msg)
6282 {
6283 case MSG_START:
6284 {
6285 if(d->d2 < 1) d->d2 = 12;
6286 else if(d->d2 > 17) d->d2 = 17;
6287 break;
6288 }
6289
6290 case MSG_DRAW:
6291 {
6292 if(!d->d1 || (d->flags&D_DISABLED))
6293 {
6294 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6295 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6296 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6297 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6298 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6299 }
6300 else
6301 {
6302 int32_t c;
6303 switch(d->d1) //special cases
6304 {
6305 case BLACK:
6306 c = vc(0);
6307 break;
6308 case WHITE:
6309 c = vc(15);
6310 break;
6311 default:
6312 c = d->d1;
6313 break;
6314 }
6315 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6316 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6317 }
6318 break;
6319 }
6320
6321 case MSG_CLICK:
6322 {
6323 if(d->flags&(D_READONLY|D_DISABLED)) break;
6324 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6325 selcolor_dlg[3].bg = scheme[jcBOXFG];
6326 selcolor_dlg[3].fg = scheme[jcBOX];
6327 selcolor_dlg[3].d1 = d->d1;
6328 selcolor_dlg[3].d2 = d->d2;
6329 large_dialog(selcolor_dlg);
6330
6331 while(gui_mouse_b()) rest(1); //wait for mouseup
6332
6333 //!TODO Move this out of jwin, and do better palette management.
6334 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6335 PALETTE oldpal;
6336 get_palette(oldpal);
6337 bool alt = d->d2 > 16;
6338 if(!alt)
6339 {
6340 PALETTE foopal;
6341 get_palette(foopal);
6342 foopal[BLACK] = _RGB(0,0,0);
6343 foopal[WHITE] = _RGB(255,255,255);
6344 zc_set_palette(foopal);
6345 }
6346
6347 jwin_center_dialog(selcolor_dlg);
6348 int32_t val = do_zqdialog(selcolor_dlg, 3);
6349 ret = D_REDRAW;
6350
6351 zc_set_palette(oldpal);
6352 if(val == 1 || val == 3)
6353 {
6354 d->d1 = selcolor_dlg[3].d1;
6355 GUI_EVENT(d, geCHANGE_VALUE);
6356 ret |= D_REDRAWME;
6357 }
6358 if(d->flags & D_EXIT)
6359 return D_CLOSE;
6360 break;
6361 }
6362 }
6363 return ret;
6364 }
6365
6366 static DIALOG alert_dialog[] =
6367 {
6368 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6369 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6370 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6371 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6372 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6373 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6374 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6375 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6376 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6377 };
6378
6379 #define A_S1 1
6380 #define A_S2 2
6381 #define A_S3 3
6382 #define A_B1 4
6383 #define A_B2 5
6384 #define A_B3 6
6385
6386 /* jwin_alert3:
6387 * Displays a simple alert box, containing three lines of text (s1-s3),
6388 * and with either one, two, or three buttons. The text for these buttons
6389 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6390 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6391 * which button was selected.
6392 */
6393 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6394 {
6395 int32_t maxlen = 0;
6396 int32_t len1, len2, len3;
6397 int32_t avg_w = text_length(font, " ");
6398 int32_t avg_h = text_height(font)+1;
6399 int32_t buttons = 0;
6400 int32_t yofs = (title ? 22 : 0);
6401 int32_t b[3];
6402 int32_t c;
6403
6404 #define SORT_OUT_BUTTON(x) { \
6405 if (b##x) \
6406 { \
6407 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6408 alert_dialog[A_B##x].key = c##x; \
6409 alert_dialog[A_B##x].dp = (void *)b##x; \
6410 len##x = gui_strlen(b##x); \
6411 b[buttons++] = A_B##x; \
6412 } \
6413 else \
6414 { \
6415 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6416 len##x = 0; \
6417 } \
6418 }
6419
6420 if(title_font)
6421 {
6422 alert_dialog[0].dp2=title_font;
6423 }
6424
6425 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6426 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6427
6428 if(s1)
6429 {
6430 alert_dialog[A_S1].dp = (void *)s1;
6431 maxlen = text_length(font, s1);
6432 }
6433
6434 if(s2)
6435 {
6436 alert_dialog[A_S2].dp = (void *)s2;
6437 len1 = text_length(font, s2);
6438
6439 if(len1 > maxlen)
6440 maxlen = len1;
6441 }
6442
6443 if(s3)
6444 {
6445 alert_dialog[A_S3].dp = (void *)s3;
6446 len1 = text_length(font, s3);
6447
6448 if(len1 > maxlen)
6449 maxlen = len1;
6450 }
6451
6452 SORT_OUT_BUTTON(1);
6453 SORT_OUT_BUTTON(2);
6454 SORT_OUT_BUTTON(3);
6455
6456 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6457
6458 if(len1*buttons > maxlen)
6459 maxlen = len1*buttons;
6460
6461 maxlen += avg_w*4;
6462 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6463 alert_dialog[0].w = maxlen;
6464 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6465 alert_dialog[0].x + maxlen/2;
6466
6467 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6468
6469 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6470 alert_dialog[0].x + maxlen/2 - len1/2;
6471
6472 if(buttons == 3)
6473 {
6474 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6475 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6476 }
6477 else if(buttons == 2)
6478 {
6479 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6480 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6481 }
6482
6483 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6484 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6485 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6486 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6487 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6488
6489 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6490 alert_dialog[0].y + avg_h*5 + yofs;
6491
6492 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6493
6494 alert_dialog[0].dp = (void *)title;
6495 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6496
6497 jwin_center_dialog(alert_dialog);
6498 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6499
6500 clear_keybuf();
6501
6502 do
6503 {
6504 rest(1);
6505 }
6506 while(gui_mouse_b());
6507
6508 large_dialog(alert_dialog);
6509 alert_dialog[0].d1 = 0;
6510
6511 c = do_zqdialog(alert_dialog, A_B1);
6512
6513 if(c == A_B1)
6514 return 1;
6515 else if(c == A_B2)
6516 return 2;
6517 else
6518 return 3;
6519 }
6520
6521 /* jwin_alert:
6522 * Displays a simple alert box, containing three lines of text (s1-s3),
6523 * and with either one or two buttons. The text for these buttons is passed
6524 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6525 * Returns 1 or 2 depending on which button was selected.
6526 */
6527 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6528 {
6529 int32_t ret;
6530
6531 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6532
6533 if(ret > 2)
6534 ret = 2;
6535
6536 return ret;
6537 }
6538
6539 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6540 {
6541 ASSERT(d);
6542 ASSERT(d->dp);
6543 #define AUTOBUF_SIZE 8092
6544 static char auto_buf[AUTOBUF_SIZE] = {0};
6545 static int32_t auto_inds[50] = {0};
6546
6547
6548 FONT *oldfont = font;
6549
6550 if (d->dp2)
6551 font = (FONT*)d->dp2;
6552 switch(msg)
6553 {
6554 case MSG_START:
6555 {
6556 memset(auto_buf, 0, AUTOBUF_SIZE);
6557 memset(auto_inds, 0, 50);
6558 char* str = (char*)d->dp;
6559 int32_t len = strlen(str);
6560 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6561 BITMAP* dummy = create_bitmap_ex(8,8,8);
6562 for(int32_t q = 0; q < len; ++q)
6563 {
6564 switch(str[q])
6565 {
6566 case ' ': case '\t':
6567 lastWS = pos;
6568 break;
6569 case '\n': //Forced newline
6570 auto_inds[linecount++] = ++pos;
6571 curstrpos = pos;
6572 lastWS = -1;
6573 continue; //skip rest of for loop, go to next char
6574 }
6575 auto_buf[pos++] = str[q];
6576 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6577 {
6578 if(lastWS<0)
6579 {
6580 auto_buf[pos-1] = 0;
6581 auto_inds[linecount++] = pos;
6582 curstrpos = pos;
6583 auto_buf[pos++] = str[q];
6584 }
6585 else
6586 {
6587 auto_buf[lastWS] = 0;
6588 auto_inds[linecount++] = lastWS+1;
6589 curstrpos = lastWS+1;
6590 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6591 {
6592 auto_buf[pos-1] = 0;
6593 auto_inds[linecount++] = pos;
6594 curstrpos = pos;
6595 auto_buf[pos++] = str[q];
6596 }
6597 lastWS = -1;
6598 }
6599 }
6600 }
6601 destroy_bitmap(dummy);
6602 d->d2 = linecount;
6603 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6604 }
6605 break;
6606
6607 case MSG_DRAW:
6608 {
6609 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6610 int32_t linecount = d->d2;
6611
6612 int32_t yinc = text_height(font)+d->d1;
6613 int32_t y = d->y;
6614 for(int32_t q = 0; q < linecount; ++q)
6615 {
6616 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6617 y += yinc;
6618 }
6619 }
6620 break;
6621 }
6622 font = oldfont;
6623 return D_O_K;
6624 }
6625
6626 static DIALOG alert2_dialog[] =
6627 {
6628 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6629 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6630 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6631 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6632 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6633 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6634 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6635 };
6636
6637 #define A2_S1 1
6638 #define A2_B1 2
6639 #define A2_B2 3
6640 #define A2_B3 4
6641
6642 /* jwin_auto_alert3:
6643 * Displays a simple alert box, containing one line of text, auto-split
6644 * across lines using 'lenlim' and 'vspace,
6645 * and with either one, two, or three buttons. The text for these buttons
6646 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6647 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6648 * which button was selected.
6649 */
6650 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6651 {
6652 int32_t maxlen = 0;
6653 int32_t len1, len2, len3;
6654 int32_t avg_w = text_length(font, " ");
6655 int32_t avg_h = text_height(font)+1;
6656 int32_t buttons = 0;
6657 int32_t yofs = (title ? 22 : 0);
6658 int32_t b[3];
6659 int32_t c;
6660
6661 #define SORT_OUT_AUTOBUTTON(x) { \
6662 if (b##x) \
6663 { \
6664 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6665 alert2_dialog[A2_B##x].key = c##x; \
6666 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6667 len##x = gui_strlen(b##x); \
6668 b[buttons++] = A2_B##x; \
6669 } \
6670 else \
6671 { \
6672 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6673 len##x = 0; \
6674 } \
6675 }
6676
6677 if(title_font)
6678 {
6679 alert2_dialog[0].dp2=title_font;
6680 }
6681
6682 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6683
6684 if(s1)
6685 {
6686 alert2_dialog[A2_S1].dp = (void *)s1;
6687 maxlen = lenlim;
6688 }
6689
6690 SORT_OUT_AUTOBUTTON(1);
6691 SORT_OUT_AUTOBUTTON(2);
6692 SORT_OUT_AUTOBUTTON(3);
6693
6694 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6695
6696 if(len1*buttons > maxlen)
6697 maxlen = len1*buttons;
6698
6699 maxlen += avg_w*4;
6700 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6701
6702 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6703 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6704 alert2_dialog[A2_S1].w = lenlim;
6705 alert2_dialog[A2_S1].d1 = vspace;
6706
6707 large_dialog(alert2_dialog);
6708 alert2_dialog[0].d1 = 0;
6709
6710 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6711
6712 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6713 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6714 alert2_dialog[A2_S1].w = lenlim;
6715 alert2_dialog[A2_S1].d1 = vspace;
6716
6717 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6718
6719 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6720 alert2_dialog[0].x + maxlen/2 - len1/2;
6721
6722 if(buttons == 3)
6723 {
6724 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6725 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6726 }
6727 else if(buttons == 2)
6728 {
6729 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6730 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6731 }
6732
6733 alert2_dialog[0].w = maxlen;
6734 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6735 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6736 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6737
6738 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6739
6740 alert2_dialog[0].dp = (void *)title;
6741 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6742
6743 jwin_center_dialog(alert2_dialog);
6744 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6745
6746 clear_keybuf();
6747
6748 do
6749 {
6750 rest(1);
6751 }
6752 while(gui_mouse_b());
6753
6754 large_dialog(alert2_dialog);
6755 alert2_dialog[0].d1 = 0;
6756
6757 c = do_zqdialog(alert2_dialog, A2_B1);
6758
6759 if(c == A2_B1)
6760 return 1;
6761 else if(c == A2_B2)
6762 return 2;
6763 else
6764 return 3;
6765 }
6766
6767 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6768 {
6769 int32_t ret;
6770
6771 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6772
6773 if(ret > 2)
6774 ret = 2;
6775
6776 return ret;
6777 }
6778
6779 int32_t last_droplist_sel = -1;
6780 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6781 {
6782 //these are here to bypass compiler warnings about unused arguments
6783 d=d;
6784 c=c;
6785
6786 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6787 return D_CLOSE;
6788
6789 return D_O_K;
6790 }
6791
6792 static DIALOG droplist_dlg[] =
6793 {
6794 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6795 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6796 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6797 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6798 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6799 };
6800
6801 static int32_t droplist(DIALOG *d)
6802 {
6803 ListData *data = (ListData *)d->dp;
6804 int32_t d1 = d->d1;
6805 int32_t listsize, x, y, w, h, max_w;
6806 auto oz = gui_mouse_z();
6807
6808 data->listFunc(-1, &listsize);
6809 y = d->y + d->h;
6810 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6811
6812 if(y+h >= zq_screen_h)
6813 {
6814 y = d->y - h;
6815 }
6816
6817 x = d->x;
6818 w = d->w;
6819 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6820
6821 for(int32_t i=0; i<listsize; ++i)
6822 {
6823 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6824 }
6825
6826 if(x+w >= zq_screen_w)
6827 {
6828 x=zq_screen_w-w;
6829 }
6830
6831 droplist_dlg[1] = *d;
6832 droplist_dlg[1].proc = &jwin_abclist_proc;
6833 droplist_dlg[1].flags = D_EXIT + D_USER;
6834 droplist_dlg[1].x = x;
6835 droplist_dlg[1].y = y;
6836 droplist_dlg[1].w = w;
6837 droplist_dlg[1].h = h;
6838 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6839
6840 // cancel
6841 droplist_dlg[0].x = 0;
6842 droplist_dlg[0].y = 0;
6843 droplist_dlg[0].w = zq_screen_w;
6844 droplist_dlg[0].h = zq_screen_h;
6845
6846 if(do_zq_subdialog(droplist_dlg,1)==1)
6847 {
6848 position_mouse_z(oz);
6849 return droplist_dlg[1].d1;
6850 }
6851
6852 position_mouse_z(oz);
6853 return d1;
6854 }
6855
6856 /* jwin_droplist_proc:
6857 * A drop list...
6858 */
6859 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6860 {
6861 int32_t ret;
6862 int32_t down=0, last_draw=0;
6863 int32_t d1;
6864
6865 switch(msg)
6866 {
6867 case MSG_CLICK:
6868 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6869 goto dropit;
6870
6871 break;
6872
6873 case MSG_KEY:
6874 goto dropit;
6875 break;
6876 }
6877
6878 d1 = d->d1;
6879 ret = jwin_list_proc(msg,d,c);
6880
6881 if(d->d1!=d->d2)
6882 {
6883 d->d1=d->d2;
6884 jwin_droplist_proc(MSG_DRAW, d, 0);
6885 }
6886
6887 if(d1 != d->d1)
6888 {
6889 GUI_EVENT(d, geCHANGE_SELECTION);
6890 if(d->flags&D_EXIT)
6891 ret |= D_CLOSE;
6892 }
6893
6894 if(msg == MSG_DRAW)
6895 {
6896 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6897 }
6898
6899 return ret;
6900
6901 dropit:
6902 last_draw = 0;
6903
6904 while(gui_mouse_b())
6905 {
6906 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6907
6908 if(down!=last_draw)
6909 {
6910 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6911 last_draw = down;
6912 update_hw_screen();
6913 }
6914
6915 clear_keybuf();
6916 rest(1);
6917 }
6918
6919 if(!down)
6920 {
6921 return D_O_K;
6922 }
6923
6924 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6925
6926 d1 = d->d1;
6927 d->d2 = d->d1 = droplist(d);
6928
6929 object_message(d, MSG_DRAW, 0);
6930
6931 while(gui_mouse_b())
6932 {
6933 clear_keybuf();
6934 rest(1);
6935 update_hw_screen();
6936 }
6937
6938 if(d1!=d->d1)
6939 GUI_EVENT(d, geCHANGE_SELECTION);
6940
6941 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6942 }
6943
6944
6945 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6946 {
6947 ListData *data = (ListData *)d->dp;
6948 if(msg == MSG_START) wipe_abc_keypresses();
6949
6950 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_CMD_FLAG))
6951 return D_O_K;
6952
6953 if(abc_patternmatch) // Search style pattern match.
6954 {
6955 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6956 {
6957 int32_t max,dummy,h;
6958
6959 h = ((d->h-3) / text_height(*data->font))-1;
6960 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6961 for ( int32_t q = 0; q < 1023; ++q )
6962 {
6963 if ( !(abc_keypresses[q]) )
6964 {
6965 abc_keypresses[q] = (char)c;
6966 break;
6967 }
6968 }
6969 data->listFunc(-1, &max);
6970
6971 int32_t cur = d->d1;
6972 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6973 char tmp[1024] = { 0 };
6974 char lsttmp[1024] = { 0 };
6975 int32_t lastmatches[32768] = {0};
6976 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6977 int32_t lmindx = 0;
6978
6979 bool foundmatch = false;
6980 bool numsearch = true;
6981 for ( int32_t q = 0; q < 1023; ++q )
6982 {
6983 if(!abc_keypresses[q]) break;
6984 if(!isdigit(abc_keypresses[q]))
6985 {
6986 if(q == 0 && abc_keypresses[q] == '-')
6987 continue;
6988 numsearch = false;
6989 break;
6990 }
6991 }
6992 if(numsearch) //Indexed search, first
6993 {
6994 int32_t num = atoi(abc_keypresses);
6995 //Find a different indexing type in the strings?
6996 if(!foundmatch)
6997 {
6998 char buf[16];
6999 if(num < 0) sprintf(buf, "(%04d)", num);
7000 else sprintf(buf, "(%03d)", num);
7001 std::string cmp = buf;
7002 for(int32_t listpos = 0; listpos < max; ++listpos)
7003 {
7004 std::string str((data->listFunc(listpos,&dummy)));
7005 size_t trimpos = str.find_last_not_of("-(0123456789)");
7006 if(trimpos != std::string::npos) ++trimpos;
7007 str.erase(0, trimpos);
7008 if(cmp == str)
7009 {
7010 d->d1 = listpos;
7011 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7012 foundmatch = true;
7013 break;
7014 }
7015 }
7016 }
7017 //Search for match with first number in string?
7018 if(!foundmatch)
7019 {
7020 auto buf = fmt::format("{}", num);
7021 for(int32_t listpos = 0; listpos < max; ++listpos)
7022 {
7023 std::string str((data->listFunc(listpos,&dummy)));
7024 size_t pos1 = -1;
7025 do
7026 {
7027 pos1 = str.find_first_of("-0123456789", pos1+1);
7028 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
7029 if(pos1 == string::npos)
7030 continue;
7031 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
7032 if(pos2 == string::npos)
7033 continue;
7034 str = str.substr(pos1,pos2-pos1);
7035 if(buf == str)
7036 {
7037 d->d1 = listpos;
7038 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7039 foundmatch = true;
7040 break;
7041 }
7042 }
7043 }
7044 }
7045 if(!foundmatch)
7046 {
7047 strcpy(tmp, abc_keypresses);
7048 for ( int32_t listpos = 0; listpos < max; ++listpos )
7049 {
7050 memset(lsttmp, 0, 1024);
7051 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
7052
7053 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
7054 {
7055 d->d1 = listpos;
7056 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7057 foundmatch = true;
7058 break;
7059 }
7060 }
7061 }
7062 if(foundmatch)
7063 GUI_EVENT(d, geCHANGE_SELECTION);
7064 d->flags |= D_DIRTY;
7065 if ( gui_mouse_b() ) wipe_abc_keypresses();
7066 return foundmatch ? D_USED_CHAR : D_O_K;
7067 }
7068 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7069 {
7070 for ( int32_t q = 1023; q >= 0; --q )
7071 {
7072 if ( abc_keypresses[q] )
7073 {
7074 d->flags |= D_DIRTY;
7075 abc_keypresses[q] = '\0'; break;
7076 }
7077 }
7078 return D_USED_CHAR;
7079 }
7080 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7081 }
7082 else // Windows Explorer style jumping
7083 {
7084 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7085 {
7086 int32_t max,dummy,h,i;
7087
7088 h = (d->h-3) / text_height(*data->font);
7089 c = toupper(c&0xFF);
7090
7091 data->listFunc(-1, &max);
7092
7093 int32_t cur = d->d1;
7094 bool foundmatch = false;
7095 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7096 {
7097 if(i>=max) i=0;
7098 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7099 {
7100 d->d1 = i;
7101 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7102 foundmatch = true;
7103 break;
7104 }
7105 }
7106
7107 d->flags |= D_DIRTY;
7108 return foundmatch ? D_USED_CHAR : D_O_K;
7109 }
7110 }
7111 if ( gui_mouse_b() ) { wipe_abc_keypresses(); }
7112 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7113 }
7114
7115 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7116 {
7117
7118 FONT *oldfont = font;
7119
7120 if(d->dp2)
7121 {
7122 font = (FONT *)d->dp2;
7123 }
7124
7125 int32_t rval = jwin_check_proc(msg, d, c);
7126 font = oldfont;
7127 return rval;
7128 }
7129
7130 /* jwin_check_proc:
7131 * Who needs C++ after all? This is derived from d_button_proc,
7132 * but overrides the drawing routine to provide a check box.
7133 */
7134 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7135 {
7136 //these are here to bypass compiler warnings about unused arguments
7137 c=c;
7138 int32_t x;
7139 int32_t bx=0, tl=0;
7140 int32_t tx=d->x;
7141 ASSERT(d);
7142
7143 switch(msg)
7144 {
7145 case MSG_DRAW:
7146 x = d->x;
7147
7148 if(!(d->d1))
7149 {
7150 if(d->dp)
7151 {
7152 if(d->flags & D_DISABLED)
7153 {
7154 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7155 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7156 bx=tl+text_height(font)/2;
7157 }
7158 else
7159 {
7160 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7161 bx=tl+text_height(font)/2;
7162 }
7163 }
7164 }
7165
7166 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7167
7168 if(!(d->flags & D_DISABLED))
7169 {
7170 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7171 }
7172
7173 if(d->d1)
7174 {
7175 tx=x+bx+d->h-1+(text_height(font)/2);
7176
7177 if(d->dp)
7178 {
7179 if(d->flags & D_DISABLED)
7180 {
7181 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7182 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7183 }
7184 else
7185 {
7186 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7187 }
7188 }
7189 }
7190
7191 if(d->flags & D_SELECTED)
7192 {
7193 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7194 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7195 }
7196
7197 d->w=int32_t(text_height(font)*1.5);
7198
7199 if(d->dp)
7200 {
7201 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7202 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7203 d->w+=tl+1;
7204 }
7205
7206 return D_O_K;
7207 break;
7208 }
7209
7210 return d_jwinbutton_proc(msg, d, 0);
7211 }
7212
7213 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7214 {
7215 FONT *oldfont = font;
7216
7217 if(d->dp2)
7218 {
7219 font = (FONT *)d->dp2;
7220 }
7221
7222 int32_t rval = jwin_radio_proc(msg, d, c);
7223 font = oldfont;
7224 return rval;
7225 }
7226
7227 /* jwin_radio_proc:
7228 * GUI procedure for radio buttons.
7229 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7230 * dp-text to appear as label to the right of the button.
7231 */
7232 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7233 {
7234 int32_t x, center, r, ret, tl=0, tx;
7235 ASSERT(d);
7236
7237 switch(msg)
7238 {
7239 case MSG_DRAW:
7240 // tx=d->x+d->h-1+text_height(font);
7241 tx=d->x+int32_t(text_height(font)*1.5);
7242
7243 if(d->dp)
7244 {
7245 if(d->flags & D_DISABLED)
7246 {
7247 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7248 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7249 }
7250 else
7251 {
7252 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7253 }
7254 }
7255
7256 x = d->x;
7257 r = d->h/2;
7258
7259 center = x+r;
7260 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7261
7262 switch(d->d2)
7263 {
7264 case 1:
7265 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7266
7267 if(!(d->flags & D_DISABLED))
7268 {
7269 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7270 }
7271
7272 if(d->flags & D_SELECTED)
7273 {
7274 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7275 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7276 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7277 }
7278
7279 break;
7280
7281 default:
7282 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7283 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7284 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7285 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7286 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7287
7288 if(d->flags & D_SELECTED)
7289 {
7290 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7291 }
7292
7293 break;
7294 }
7295
7296 if(d->dp)
7297 {
7298 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7299 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7300 d->w=tl+int32_t(text_height(font)*1.5)+1;
7301 }
7302
7303 return D_O_K;
7304
7305 case MSG_KEY:
7306 case MSG_CLICK:
7307 if(d->flags & D_SELECTED)
7308 {
7309 return D_O_K;
7310 }
7311
7312 break;
7313
7314 case MSG_RADIO:
7315 if((c == d->d1) && (d->flags & D_SELECTED))
7316 {
7317 d->flags &= ~D_SELECTED;
7318 object_message(d, MSG_DRAW, 0);
7319 }
7320
7321 break;
7322 }
7323
7324 ret = d_jwinbutton_proc(msg, d, 0);
7325
7326 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7327 {
7328 d->flags &= ~D_SELECTED;
7329 broadcast_dialog_message(MSG_RADIO, d->d1);
7330 d->flags |= D_SELECTED;
7331 GUI_EVENT(d, geRADIO);
7332 }
7333
7334 return ret;
7335 }
7336
7337
7338 /* 1.5k lookup table for color matching */
7339 uint32_t col_diff[3*128];
7340
7341 /* bestfit_init:
7342 * Color matching is done with weighted squares, which are much faster
7343 * if we pregenerate a little lookup table...
7344 */
7345 77 void bestfit_init(void)
7346 {
7347 int32_t i;
7348
7349 77 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7350
7351
2/2
✓ Branch 0 taken 4851 times.
✓ Branch 1 taken 77 times.
4928 for(i=1; i<64; i++)
7352 {
7353 4851 int32_t k = i * i;
7354 4851 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7355 4851 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7356 4851 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7357 4851 }
7358 77 }
7359
7360
7361
7362 /* bestfit_color:
7363 * Searches a palette for the color closest to the requested R, G, B value.
7364 */
7365 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7366 {
7367 int32_t i, coldiff, lowest, bestfit;
7368
7369 if(col_diff[1] == 0)
7370 bestfit_init();
7371
7372 bestfit = start;
7373 lowest = INT_MAX;
7374
7375 i = start;
7376
7377 while(i<PAL_SIZE&&i<=end)
7378 {
7379 AL_CONST RGB *rgb = &pal[i];
7380 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7381
7382 if(coldiff < lowest)
7383 {
7384 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7385
7386 if(coldiff < lowest)
7387 {
7388 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7389
7390 if(coldiff < lowest)
7391 {
7392 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7393
7394 if(coldiff == 0)
7395 {
7396 return bestfit;
7397 }
7398
7399 lowest = coldiff;
7400 }
7401 }
7402 }
7403
7404 i++;
7405 }
7406
7407 return bestfit;
7408 }
7409
7410
7411 /* makecol8:
7412 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7413 * If the global rgb_map table is initialised, it uses that, otherwise
7414 * it searches through the current palette to find the best match.
7415 */
7416 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7417 {
7418 return table->data[r>>3][g>>3][b>>3];
7419 }
7420
7421
7422 /* create_rgb_table:
7423 * Fills an RGB_MAP lookup table with conversion data for the specified
7424 * palette. This is the faster version by Jan Hubicka.
7425 *
7426 * Uses alg. similar to floodfill - it adds one seed per every color in
7427 * palette to its best position. Then areas around seed are filled by
7428 * same color because it is best approximation for them, and then areas
7429 * about them etc...
7430 *
7431 * It does just about 80000 tests for distances and this is about 100
7432 * times better than normal 256*32000 tests so the calculation time
7433 * is now less than one second at all computers I tested.
7434 */
7435 8418 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal_8bit, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7436 {
7437 #define UNUSED 65535
7438 #define LAST 65532
7439
7440 // Allegro has been modified to use an 8 bit palette, but this method and RGB_MAP still use 6 bit.
7441 PALETTE pal;
7442
2/2
✓ Branch 0 taken 2155008 times.
✓ Branch 1 taken 8418 times.
2163426 for (int i = 0; i < 256; i++)
7443 {
7444 2155008 pal[i] = pal_8bit[i];
7445 2155008 pal[i].r /= 4;
7446 2155008 pal[i].g /= 4;
7447 2155008 pal[i].b /= 4;
7448 2155008 }
7449
7450 /* macro add adds to single linked list */
7451 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7452 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7453 (last = (i))) : 0)
7454
7455 /* same but w/o checking for first element */
7456 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7457 next[last] = (i), \
7458 (last = (i))) : 0)
7459
7460 /* calculates distance between two colors */
7461 #define dist(a1, a2, a3, b1, b2, b3) \
7462 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7463 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7464 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7465
7466 /* converts r,g,b to position in array and back */
7467 #define pos(r, g, b) \
7468 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7469
7470 #define depos(pal, r, g, b) \
7471 ((b) = ((pal) & 31) * 2, \
7472 (g) = (((pal) >> 5) & 31) * 2, \
7473 (r) = (((pal) >> 10) & 31) * 2)
7474
7475 /* is current color better than pal1? */
7476 #define better(r1, g1, b1, pal1) \
7477 (((int32_t)dist((r1), (g1), (b1), \
7478 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7479
7480 /* checking of position */
7481 #define dopos(rp, gp, bp, ts) \
7482 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7483 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7484 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7485 i = first + rp * 32 * 32 + gp * 32 + bp; \
7486 if (!data[i]) { \
7487 data[i] = val; \
7488 add1(i); \
7489 } \
7490 else if ((ts) && (data[i] != val)) { \
7491 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7492 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7493 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7494 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7495 data[i] = val; \
7496 add1(i); \
7497 } \
7498 } \
7499 }
7500
7501 int32_t i, curr, r, g, b, val, dist2;
7502 uint32_t r2, g2, b2;
7503 uint16_t next[32*32*32];
7504 uint8_t *data;
7505 8418 int32_t first = LAST;
7506 8418 int32_t last = LAST;
7507 8418 int32_t count = 0;
7508 8418 int32_t cbcount = 0;
7509
7510 #define AVERAGE_COUNT 18000
7511
7512
2/2
✓ Branch 0 taken 8352 times.
✓ Branch 1 taken 66 times.
8418 if(col_diff[1] == 0)
7513 66 bestfit_init();
7514
7515 8418 memset(next, 255, sizeof(next));
7516 8418 memset(table->data, 0, sizeof(char)*32*32*32);
7517
7518 8418 data = (uint8_t *)table->data;
7519
7520 /* add starting seeds for floodfill */
7521
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 277794 times.
✓ Branch 2 taken 269376 times.
✓ Branch 3 taken 8418 times.
277794 for(i=start; i<PAL_SIZE&&i<=end; i++)
7522 {
7523 269376 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7524
7525
2/2
✓ Branch 0 taken 96521 times.
✓ Branch 1 taken 172855 times.
269376 if(next[curr] == UNUSED)
7526 {
7527 172855 data[curr] = i;
7528
3/4
✓ Branch 0 taken 172855 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 164437 times.
✓ Branch 3 taken 8418 times.
172855 add(curr);
7529 172855 }
7530 269376 }
7531
7532 /* main floodfill: two versions of loop for faster growing in blue axis */
7533
2/2
✓ Branch 0 taken 8418 times.
✓ Branch 1 taken 160538025 times.
160546443 while(first < LAST)
7534 {
7535 160538025 depos(first, r, g, b);
7536
7537 /* calculate distance of current color */
7538 160538025 val = data[first];
7539 160538025 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7540 160538025 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7541 160538025 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7542
7543 /* try to grow to all directions */
7544 #ifdef _MSC_VER
7545 #pragma warning(disable:4127)
7546 #endif
7547
11/12
✓ Branch 0 taken 4325531 times.
✓ Branch 1 taken 156212494 times.
✓ Branch 2 taken 142438931 times.
✓ Branch 3 taken 13773563 times.
✓ Branch 4 taken 13773563 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 130987632 times.
✓ Branch 7 taken 11451299 times.
✓ Branch 8 taken 3078791 times.
✓ Branch 9 taken 8372508 times.
✓ Branch 10 taken 19743 times.
✓ Branch 11 taken 8352765 times.
302976956 dopos(0, 0, 1, 1);
7548
11/12
✓ Branch 0 taken 7352756 times.
✓ Branch 1 taken 153185269 times.
✓ Branch 2 taken 153174733 times.
✓ Branch 3 taken 10536 times.
✓ Branch 4 taken 10536 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 151480737 times.
✓ Branch 7 taken 1693996 times.
✓ Branch 8 taken 715114 times.
✓ Branch 9 taken 978882 times.
✓ Branch 10 taken 966248 times.
✓ Branch 11 taken 12634 times.
313712758 dopos(0, 0,-1, 1);
7549
11/12
✓ Branch 0 taken 4395242 times.
✓ Branch 1 taken 156142783 times.
✓ Branch 2 taken 155243020 times.
✓ Branch 3 taken 899763 times.
✓ Branch 4 taken 899763 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 121012961 times.
✓ Branch 7 taken 34230059 times.
✓ Branch 8 taken 34166381 times.
✓ Branch 9 taken 63678 times.
✓ Branch 10 taken 24196 times.
✓ Branch 11 taken 39482 times.
315781045 dopos(1, 0, 0, 1);
7550
11/12
✓ Branch 0 taken 6738301 times.
✓ Branch 1 taken 153799724 times.
✓ Branch 2 taken 153788668 times.
✓ Branch 3 taken 11056 times.
✓ Branch 4 taken 11056 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 115675664 times.
✓ Branch 7 taken 38113004 times.
✓ Branch 8 taken 31096219 times.
✓ Branch 9 taken 7016785 times.
✓ Branch 10 taken 6572894 times.
✓ Branch 11 taken 443891 times.
314326693 dopos(-1, 0, 0, 1);
7551
11/12
✓ Branch 0 taken 5584912 times.
✓ Branch 1 taken 154953113 times.
✓ Branch 2 taken 133156803 times.
✓ Branch 3 taken 21796310 times.
✓ Branch 4 taken 21796310 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 112494936 times.
✓ Branch 7 taken 20661867 times.
✓ Branch 8 taken 3510678 times.
✓ Branch 9 taken 17151189 times.
✓ Branch 10 taken 14971354 times.
✓ Branch 11 taken 2179835 times.
293694828 dopos(0, 1, 0, 1);
7552
11/12
✓ Branch 0 taken 4294750 times.
✓ Branch 1 taken 156243275 times.
✓ Branch 2 taken 156028312 times.
✓ Branch 3 taken 214963 times.
✓ Branch 4 taken 214963 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 143738563 times.
✓ Branch 7 taken 12289749 times.
✓ Branch 8 taken 12168207 times.
✓ Branch 9 taken 121542 times.
✓ Branch 10 taken 90494 times.
✓ Branch 11 taken 31048 times.
316566337 dopos(0,-1, 0, 1);
7553 #ifdef _MSC_VER
7554 #pragma warning(default:4127)
7555 #endif
7556
7557 /* faster growing of blue direction */
7558
4/4
✓ Branch 0 taken 153185269 times.
✓ Branch 1 taken 7352756 times.
✓ Branch 2 taken 715114 times.
✓ Branch 3 taken 152470155 times.
160538025 if((b > 0) && (data[first-1] == val))
7559 {
7560 152470155 b -= 2;
7561 152470155 first--;
7562 152470155 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7563
7564 #ifdef _MSC_VER
7565 #pragma warning(disable:4127)
7566 #endif
7567
5/6
✓ Branch 0 taken 6327122 times.
✓ Branch 1 taken 146143033 times.
✓ Branch 2 taken 146141716 times.
✓ Branch 3 taken 1317 times.
✓ Branch 4 taken 1317 times.
✗ Branch 5 not taken.
298611871 dopos(-1, 0, 0, 0);
7568
5/6
✓ Branch 0 taken 4262654 times.
✓ Branch 1 taken 148207501 times.
✓ Branch 2 taken 148132713 times.
✓ Branch 3 taken 74788 times.
✓ Branch 4 taken 74788 times.
✗ Branch 5 not taken.
300602868 dopos(1, 0, 0, 0);
7569
5/6
✓ Branch 0 taken 4128498 times.
✓ Branch 1 taken 148341657 times.
✓ Branch 2 taken 148300842 times.
✓ Branch 3 taken 40815 times.
✓ Branch 4 taken 40815 times.
✗ Branch 5 not taken.
300770997 dopos(0,-1, 0, 0);
7570
5/6
✓ Branch 0 taken 5298903 times.
✓ Branch 1 taken 147171252 times.
✓ Branch 2 taken 146683023 times.
✓ Branch 3 taken 488229 times.
✓ Branch 4 taken 488229 times.
✗ Branch 5 not taken.
299153178 dopos(0, 1, 0, 0);
7571 #ifdef _MSC_VER
7572 #pragma warning(default:4127)
7573 #endif
7574
7575 152470155 first++;
7576 152470155 }
7577
7578 /* get next from list */
7579 160538025 i = first;
7580 160538025 first = next[first];
7581 160538025 next[i] = UNUSED;
7582
7583 /* second version of loop */
7584
2/2
✓ Branch 0 taken 6577 times.
✓ Branch 1 taken 160531448 times.
160538025 if(first != LAST)
7585 {
7586 160531448 depos(first, r, g, b);
7587
7588 160531448 val = data[first];
7589 160531448 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7590 160531448 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7591 160531448 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7592
7593 #ifdef _MSC_VER
7594 #pragma warning(disable:4127)
7595 #endif
7596
11/12
✓ Branch 0 taken 4316862 times.
✓ Branch 1 taken 156214586 times.
✓ Branch 2 taken 139548354 times.
✓ Branch 3 taken 16666232 times.
✓ Branch 4 taken 16666232 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 129895417 times.
✓ Branch 7 taken 9652937 times.
✓ Branch 8 taken 3112997 times.
✓ Branch 9 taken 6539940 times.
✓ Branch 10 taken 17631 times.
✓ Branch 11 taken 6522309 times.
300079802 dopos(0, 0, 1, 1);
7597
11/12
✓ Branch 0 taken 7425067 times.
✓ Branch 1 taken 153106381 times.
✓ Branch 2 taken 153104540 times.
✓ Branch 3 taken 1841 times.
✓ Branch 4 taken 1841 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 151452682 times.
✓ Branch 7 taken 1651858 times.
✓ Branch 8 taken 684592 times.
✓ Branch 9 taken 967266 times.
✓ Branch 10 taken 950940 times.
✓ Branch 11 taken 16326 times.
313635988 dopos(0, 0,-1, 1);
7598
11/12
✓ Branch 0 taken 4224790 times.
✓ Branch 1 taken 156306658 times.
✓ Branch 2 taken 155123652 times.
✓ Branch 3 taken 1183006 times.
✓ Branch 4 taken 1183006 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 120544677 times.
✓ Branch 7 taken 34578975 times.
✓ Branch 8 taken 34525040 times.
✓ Branch 9 taken 53935 times.
✓ Branch 10 taken 22092 times.
✓ Branch 11 taken 31843 times.
315655100 dopos(1, 0, 0, 1);
7599
11/12
✓ Branch 0 taken 6461703 times.
✓ Branch 1 taken 154069745 times.
✓ Branch 2 taken 154062114 times.
✓ Branch 3 taken 7631 times.
✓ Branch 4 taken 7631 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 115793371 times.
✓ Branch 7 taken 38268743 times.
✓ Branch 8 taken 31250494 times.
✓ Branch 9 taken 7018249 times.
✓ Branch 10 taken 6643820 times.
✓ Branch 11 taken 374429 times.
314593562 dopos(-1, 0, 0, 1);
7600
11/12
✓ Branch 0 taken 5709277 times.
✓ Branch 1 taken 154822171 times.
✓ Branch 2 taken 107623569 times.
✓ Branch 3 taken 47198602 times.
✓ Branch 4 taken 47198602 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 87704311 times.
✓ Branch 7 taken 19919258 times.
✓ Branch 8 taken 3566984 times.
✓ Branch 9 taken 16352274 times.
✓ Branch 10 taken 14837220 times.
✓ Branch 11 taken 1515054 times.
268155017 dopos(0, 1, 0, 1);
7601
11/12
✓ Branch 0 taken 4401026 times.
✓ Branch 1 taken 156130422 times.
✓ Branch 2 taken 155874431 times.
✓ Branch 3 taken 255991 times.
✓ Branch 4 taken 255991 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 143676543 times.
✓ Branch 7 taken 12197888 times.
✓ Branch 8 taken 12059227 times.
✓ Branch 9 taken 138661 times.
✓ Branch 10 taken 111817 times.
✓ Branch 11 taken 26844 times.
316405879 dopos(0,-1, 0, 1);
7602 #ifdef _MSC_VER
7603 #pragma warning(default:4127)
7604 #endif
7605
7606
4/4
✓ Branch 0 taken 156214586 times.
✓ Branch 1 taken 4316862 times.
✓ Branch 2 taken 3112997 times.
✓ Branch 3 taken 153101589 times.
160531448 if((b < 61) && (data[first + 1] == val))
7607 {
7608 153101589 b += 2;
7609 153101589 first++;
7610 153101589 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7611
7612 #ifdef _MSC_VER
7613 #pragma warning(disable:4127)
7614 #endif
7615
5/6
✓ Branch 0 taken 6127350 times.
✓ Branch 1 taken 146974239 times.
✓ Branch 2 taken 138259067 times.
✓ Branch 3 taken 8715172 times.
✓ Branch 4 taken 8715172 times.
✗ Branch 5 not taken.
291360656 dopos(-1, 0, 0, 0);
7616
5/6
✓ Branch 0 taken 4101148 times.
✓ Branch 1 taken 149000441 times.
✓ Branch 2 taken 102653083 times.
✓ Branch 3 taken 46347358 times.
✓ Branch 4 taken 46347358 times.
✗ Branch 5 not taken.
255754672 dopos(1, 0, 0, 0);
7617
5/6
✓ Branch 0 taken 4259767 times.
✓ Branch 1 taken 148841822 times.
✓ Branch 2 taken 145100875 times.
✓ Branch 3 taken 3740947 times.
✓ Branch 4 taken 3740947 times.
✗ Branch 5 not taken.
298202464 dopos(0,-1, 0, 0);
7618
5/6
✓ Branch 0 taken 5419317 times.
✓ Branch 1 taken 147682272 times.
✓ Branch 2 taken 33442223 times.
✓ Branch 3 taken 114240049 times.
✓ Branch 4 taken 114240049 times.
✗ Branch 5 not taken.
186543812 dopos(0, 1, 0, 0);
7619 #ifdef _MSC_VER
7620 #pragma warning(default:4127)
7621 #endif
7622
7623 153101589 first--;
7624 153101589 }
7625
7626 160531448 i = first;
7627 160531448 first = next[first];
7628 160531448 next[i] = UNUSED;
7629 160531448 }
7630
7631 160538025 count++;
7632
7633
2/2
✓ Branch 0 taken 158375651 times.
✓ Branch 1 taken 2162374 times.
160538025 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7634 {
7635
2/2
✓ Branch 0 taken 7366 times.
✓ Branch 1 taken 2155008 times.
2162374 if(cbcount < 256)
7636 {
7637
1/2
✓ Branch 0 taken 2155008 times.
✗ Branch 1 not taken.
2155008 if(callback)
7638 callback(cbcount);
7639
7640 2155008 cbcount++;
7641 2155008 }
7642 2162374 }
7643 }
7644
7645
1/2
✓ Branch 0 taken 8418 times.
✗ Branch 1 not taken.
8418 if(callback)
7646 while(cbcount < 256)
7647 callback(cbcount++);
7648 8418 }
7649
7650 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7651 {
7652 int32_t j=((int16_t *)bmp->line[0])[i];
7653 int32_t r=getr15(j);
7654 int32_t g=getg15(j);
7655 int32_t b=getb15(j);
7656 int32_t k=1;
7657
7658 if(i>0)
7659 {
7660 j=((int16_t *)bmp->line[0])[i-1];
7661 r+=getr15(j);
7662 g+=getg15(j);
7663 b+=getb15(j);
7664 ++k;
7665 }
7666
7667 if(i<(bmp->w-2))
7668 {
7669 j=((int16_t *)bmp->line[0])[i+1];
7670 r+=getr15(j);
7671 g+=getg15(j);
7672 b+=getb15(j);
7673 ++k;
7674 }
7675
7676 r/=k;
7677 g/=k;
7678 b/=k;
7679 return makecol15(r, g, b);
7680 }
7681
7682 // A consistent RENG (random enough number generator) for dither_rect()
7683 static uint16_t lfsr;
7684
7685 void lfsrInit()
7686 {
7687 lfsr=1;
7688 }
7689
7690 uint16_t lfsrNext()
7691 {
7692 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7693 lfsr=(lfsr>>1)|(bits<<15);
7694 return lfsr;
7695 }
7696
7697 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7698 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7699 uint8_t dest_color2)
7700 {
7701 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7702 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7703 int32_t r, g, b, direction=1;
7704 int32_t c;
7705 int32_t r1, r2, g1, g2, b1, b2;
7706 int32_t (*diff[2])[3];
7707 diff[0] = new int32_t[x2-x1+3][3];
7708 diff[1] = new int32_t[x2-x1+3][3];
7709 int32_t cdiff[3];
7710 RGB_MAP table;
7711 int32_t temp;
7712 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7713
7714 lfsrInit();
7715 clear_bitmap(dest_bmp);
7716
7717 if(x1>x2)
7718 {
7719 temp=x1;
7720 x1=x2;
7721 x2=temp;
7722 }
7723
7724 if(y1>y2)
7725 {
7726 temp=y1;
7727 y1=y2;
7728 y2=temp;
7729 }
7730
7731 if(src_color1>src_color2)
7732 {
7733 temp=src_color1;
7734 src_color1=src_color2;
7735 src_color2=temp;
7736 }
7737
7738 if(dest_color1>dest_color2)
7739 {
7740 temp=dest_color1;
7741 dest_color1=dest_color2;
7742 dest_color2=temp;
7743 }
7744
7745 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7746 r1=getr15(src_color1);
7747 r2=getr15(src_color2);
7748 g1=getg15(src_color1);
7749 g2=getg15(src_color2);
7750 b1=getb15(src_color1);
7751 b2=getb15(src_color2);
7752 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7753 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7754 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7755 memset(cdiff,0,3*sizeof(float));
7756 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7757 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7758 int32_t mc, mr, mg, mb;
7759
7760 for(int32_t i=0; i<src_bmp->w; i++)
7761 {
7762 r = mix_value(r1, r2, i, src_bmp->w-1);
7763 g = mix_value(g1, g2, i, src_bmp->w-1);
7764 b = mix_value(b1, b2, i, src_bmp->w-1);
7765 c = makecol15(r,g,b);
7766 ((int16_t *)src_bmp->line[0])[i] = c;
7767 }
7768
7769 uint8_t tempcolor, origcolor;
7770
7771 for(int32_t j=0; j<=y2-y1; ++j)
7772 {
7773 if(direction==1)
7774 {
7775 for(int32_t i=0; i<=x2-x1; ++i)
7776 {
7777 mc=((int16_t *)src_bmp->line[0])[i];
7778 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7779 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7780 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7781 cdiff[0]=bound(mr+
7782 diff[0][i][0]+
7783 diff[0][i+1][0]+
7784 diff[0][i+2][0]+
7785 cdiff[0],0,255);
7786 cdiff[1]=bound(mg+
7787 diff[0][i][1]+
7788 diff[0][i+1][1]+
7789 diff[0][i+2][1]+
7790 cdiff[1],0,255);
7791 cdiff[2]=bound(mb+
7792 diff[0][i][2]+
7793 diff[0][i+1][2]+
7794 diff[0][i+2][2]+
7795 cdiff[2],0,255);
7796 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7797 origcolor=makecol8_map(mr,mg,mb,&table);
7798 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7799 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7800 dest_bmp->line[j][i]=tempcolor;
7801 r=getr8(tempcolor);
7802 g=getg8(tempcolor);
7803 b=getb8(tempcolor);
7804 diff[1][i][0]=(cdiff[0]-r)*3/16;
7805 diff[1][i][1]=(cdiff[1]-g)*3/16;
7806 diff[1][i][2]=(cdiff[2]-b)*3/16;
7807 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7808 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7809 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7810 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7811 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7812 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7813 cdiff[0]=(cdiff[0]-r)*7/16;
7814 cdiff[1]=(cdiff[1]-g)*7/16;
7815 cdiff[2]=(cdiff[2]-b)*7/16;
7816 }
7817
7818 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7819 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7820 direction=-1;
7821 }
7822 else
7823 {
7824 for(int32_t i=x2-x1; i>=0; --i)
7825 {
7826 mc=((int16_t *)src_bmp->line[0])[i];
7827 mr=getr15(mc);
7828 mg=getg15(mc);
7829 mb=getb15(mc);
7830 cdiff[0]=bound(mr+
7831 diff[0][i][0]+
7832 diff[0][i+1][0]+
7833 diff[0][i+2][0]+
7834 cdiff[0],0,255);
7835 cdiff[1]=bound(mg+
7836 diff[0][i][1]+
7837 diff[0][i+1][1]+
7838 diff[0][i+2][1]+
7839 cdiff[1],0,255);
7840 cdiff[2]=bound(mb+
7841 diff[0][i][2]+
7842 diff[0][i+1][2]+
7843 diff[0][i+2][2]+
7844 cdiff[2],0,255);
7845 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7846 origcolor=makecol8_map(mr,mg,mb,&table);
7847 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7848 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7849 dest_bmp->line[j][i]=tempcolor;
7850 r=getr8(tempcolor);
7851 g=getg8(tempcolor);
7852 b=getb8(tempcolor);
7853 diff[1][i][0]=(cdiff[0]-r)*3/16;
7854 diff[1][i][1]=(cdiff[1]-g)*3/16;
7855 diff[1][i][2]=(cdiff[2]-b)*3/16;
7856 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7857 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7858 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7859 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7860 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7861 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7862 cdiff[0]=(cdiff[0]-r)*7/16;
7863 cdiff[1]=(cdiff[1]-g)*7/16;
7864 cdiff[2]=(cdiff[2]-b)*7/16;
7865 }
7866
7867 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7868 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7869 direction=1;
7870 }
7871 }
7872
7873 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7874 delete[] diff[1];
7875 delete[] diff[0];
7876 destroy_bitmap(src_bmp);
7877 destroy_bitmap(dest_bmp);
7878 return;
7879 }
7880
7881 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7882 {
7883 bool over=false;
7884
7885 while(gui_mouse_b())
7886 {
7887 if(mouse_in_rect(x,y,w,h))
7888 {
7889 if(!over)
7890 {
7891 vsync();
7892 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7893 over=true;
7894 update_hw_screen();
7895 }
7896 }
7897 else
7898 {
7899 if(over)
7900 {
7901 vsync();
7902 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7903 over=false;
7904 update_hw_screen();
7905 }
7906 }
7907 rest(1);
7908 }
7909
7910 return over;
7911 }
7912
7913 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7914 {
7915 bool over=false;
7916
7917 while(gui_mouse_b())
7918 {
7919 //vsync();
7920 if(mouse_in_rect(x,y,w,h))
7921 {
7922 if(!over)
7923 {
7924 vsync();
7925 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7926 over=true;
7927
7928 update_hw_screen();
7929 }
7930 }
7931 else
7932 {
7933 if(over)
7934 {
7935 vsync();
7936 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7937 over=false;
7938
7939 update_hw_screen();
7940 }
7941 }
7942 rest(1);
7943 }
7944
7945 if(over)
7946 {
7947 vsync();
7948 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7949
7950 update_hw_screen();
7951 }
7952
7953 return over;
7954 }
7955 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
7956 {
7957 bool over=false;
7958
7959 while(gui_mouse_b())
7960 {
7961 //vsync();
7962 if(mouse_in_rect(x,y,w,h))
7963 {
7964 if(!over)
7965 {
7966 vsync();
7967 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
7968 over=true;
7969
7970 update_hw_screen();
7971 }
7972 }
7973 else
7974 {
7975 if(over)
7976 {
7977 vsync();
7978 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
7979 over=false;
7980
7981 update_hw_screen();
7982 }
7983 }
7984 rest(1);
7985 }
7986
7987 if(over)
7988 {
7989 vsync();
7990 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
7991
7992 update_hw_screen();
7993 }
7994
7995 return over;
7996 }
7997
7998 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
7999 {
8000 int32_t i;
8001 int32_t tx;
8002 int32_t sd=2; //selected delta
8003 TABPANEL *panel=(TABPANEL *)d->dp;
8004 DIALOG *panel_dialog=NULL, *current_object=NULL;
8005 int32_t selected=0;
8006 int32_t counter=0;
8007 ASSERT(d);
8008 int32_t temp_d, temp_d2;
8009
8010 if(d->dp==NULL) return D_O_K;
8011
8012 panel_dialog=(DIALOG *)d->dp3;
8013
8014 if (msg != MSG_START && msg != MSG_END)
8015 {
8016 bool redraw = false;
8017 for (i = 0; panel[i].text; ++i)
8018 {
8019 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8020 {
8021 for (counter = 0; counter < panel[i].objects; counter++)
8022 {
8023 current_object = panel_dialog + (panel[i].dialog[counter]);
8024 current_object->flags &= ~D_HIDDEN;
8025 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8026 redraw = true;
8027 }
8028 }
8029 else
8030 {
8031 for (counter = 0; counter < panel[i].objects; counter++)
8032 {
8033 current_object = panel_dialog + (panel[i].dialog[counter]);
8034 current_object->flags |= D_HIDDEN;
8035 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8036 redraw = true;
8037 }
8038 }
8039
8040 /*if (d->flags & D_HIDDEN)
8041 {
8042 for(counter=0; counter<panel[i].objects; counter++)
8043 {
8044 current_object=panel_dialog+(panel[i].dialog[counter]);
8045 current_object->x=zq_screen_w*3;
8046 current_object->y=zq_screen_h*3;
8047 }
8048 }*/
8049 }
8050 if (redraw)
8051 broadcast_dialog_message(MSG_DRAW, 0);
8052 }
8053 FONT *oldfont = font;
8054 switch(msg)
8055 {
8056 case MSG_DRAW:
8057 {
8058 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8059 {
8060 if(d->dp2)
8061 {
8062 font = (FONT *)d->dp2;
8063 }
8064
8065 panel_dialog=(DIALOG *)d->dp3;
8066 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8067 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8068 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8069 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8070 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8071 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8072 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8073 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8074 tx=d->x;
8075
8076 if(d->dp)
8077 {
8078 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8079 {
8080 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8081 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8082 }
8083
8084 tx+=2;
8085
8086 for(i=0; panel[i].text; ++i)
8087 {
8088 if(panel[i].flags&D_SELECTED)
8089 {
8090 selected=i;
8091 }
8092 }
8093
8094 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8095 {
8096 sd=(panel[i].flags&D_SELECTED)?0:2;
8097
8098 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8099 {
8100 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8101 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8102 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8103 }
8104
8105 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8106 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8107
8108 if(!(panel[i].flags&D_SELECTED))
8109 {
8110 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8111 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8112 }
8113
8114 tx+=4;
8115 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8116 tx+=text_length(font, (char *)panel[i].text)+10;
8117
8118 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8119 {
8120 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8121 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8122 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8123 }
8124
8125 tx++;
8126 }
8127
8128 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8129 {
8130 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8131 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8132 }
8133 }
8134
8135 if((tx+(2-sd))<(d->x+d->w))
8136 {
8137 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8138 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8139 }
8140
8141 font = oldfont;
8142
8143 //what dialog is this tab control in (programmer must set manually)
8144 panel_dialog=(DIALOG *)d->dp3;
8145
8146 //for each object handled by the currently selected tab...
8147 for(counter=0; counter<panel[selected].objects; counter++)
8148 {
8149 //assign current_object to one of the controls handled by the tab
8150 current_object=panel_dialog+(panel[selected].dialog[counter]);
8151 //remember the x and y positions of the control
8152 current_object->x=panel[selected].xy[counter*2];
8153 current_object->y=panel[selected].xy[counter*2+1];
8154 object_message(current_object, MSG_DRAW, 0);
8155 }
8156
8157 //if there was a previously selected tab...
8158 if((d->d1&0x00FF)!=0x00FF)
8159 {
8160 //for each object handled by the tab
8161 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8162 {
8163 //assign current_object to one of the controls handled by the tab
8164 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8165 // //remember the x and y positions of the control
8166 // panel[d->d1].xy[counter*2]=current_object->x;
8167 // panel[d->d1].xy[counter*2+1]=current_object->y;
8168 current_object->x=zq_screen_w*3;
8169 current_object->y=zq_screen_h*3;
8170 }
8171 }
8172 }
8173 }
8174 break;
8175
8176 case MSG_CLICK:
8177 {
8178 d->d1&=0xFF00;
8179 d->d1|=0x00FF;
8180 if(d->dp2)
8181 {
8182 font = (FONT *)d->dp2;
8183 }
8184
8185 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8186 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8187 {
8188 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8189 {
8190 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8191 {
8192 temp_d=((d->d1&0xFF00)>>8);
8193 temp_d2=(d->d1&0x00FF);
8194
8195 if(temp_d>0)
8196 {
8197 --temp_d;
8198 }
8199
8200 d->d1=(temp_d<<8)|temp_d2;
8201 d->flags|=D_DIRTY;
8202 }
8203 }
8204 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8205 {
8206 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8207 {
8208 temp_d=((d->d1&0xFF00)>>8);
8209 temp_d2=(d->d1&0x00FF);
8210
8211 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8212 {
8213 ++temp_d;
8214 }
8215
8216 d->d1=(temp_d<<8)|temp_d2;
8217 d->flags|=D_DIRTY;
8218 }
8219 }
8220 }
8221 else
8222 {
8223 d_tab_proc(msg, d, c);
8224 }
8225 font = oldfont;
8226 jwin_tab_proc(MSG_IDLE,d,0);
8227 }
8228 break;
8229
8230 default:
8231 return d_tab_proc(msg, d, c);
8232 break;
8233 }
8234
8235 panel_dialog=(DIALOG *)d->dp3;
8236
8237 if(d->flags & D_HIDDEN)
8238 {
8239 for(i=0; panel[i].text; ++i)
8240 {
8241 for(counter=0; counter<panel[i].objects; counter++)
8242 {
8243 current_object=panel_dialog+(panel[i].dialog[counter]);
8244 current_object->x=zq_screen_w*3;
8245 current_object->y=zq_screen_h*3;
8246 }
8247 }
8248
8249 //d->x=zq_screen_w*3;
8250 //d->y=zq_screen_h*3;
8251 }
8252 else
8253 {
8254 for(i=0; panel[i].text; ++i)
8255 {
8256 for(counter=0; counter<panel[i].objects; counter++)
8257 {
8258 current_object=panel_dialog+(panel[i].dialog[counter]);
8259 current_object->x=panel[i].xy[counter*2];
8260 current_object->y=panel[i].xy[counter*2+1];
8261 }
8262 }
8263
8264 // d->x=zq_screen_w*3;
8265 //d->y=zq_screen_h*3;
8266 }
8267
8268 return broadcast_dialog_message(MSG_IDLE, 0);
8269
8270 // return D_O_K;
8271 }
8272
8273 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8274 {
8275 int32_t w=0;
8276
8277 for(size_t i=first_tab; i < panel->getSize(); i++)
8278 {
8279 w+=text_length(font, panel->getName(i))+15;
8280
8281 if(w>x)
8282 {
8283 return i;
8284 }
8285 }
8286
8287 return -1;
8288 }
8289 int32_t tabs_width(GUI::TabPanel *panel)
8290 {
8291 int32_t w=0;
8292
8293 for(size_t i=0; i < panel->getSize(); ++i)
8294 {
8295 w+=text_length(font, panel->getName(i))+15;
8296 }
8297
8298 return w+1;
8299 }
8300 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8301 {
8302 return (tabs_width(panel)>maxwidth);
8303 }
8304 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8305 {
8306 size_t i;
8307 int32_t w=0;
8308
8309 if(uses_tab_arrows(panel, maxwidth))
8310 {
8311 maxwidth-=28;
8312 }
8313
8314 for(i=first_tab; i < panel->getSize(); ++i)
8315 {
8316 w+=text_length(font, panel->getName(i))+15;
8317
8318 if(w>maxwidth)
8319 {
8320 return i-1;
8321 }
8322 }
8323
8324 return i-1;
8325 }
8326 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8327 {
8328 size_t i=0;
8329 int32_t w=0;
8330
8331 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8332 {
8333 w+=text_length(font, panel->getName(i))+15;
8334 }
8335
8336 return w+1;
8337 }
8338
8339 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8340 {
8341 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8342 }
8343
8344 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8345 {
8346 assert(d->flags&D_NEW_GUI);
8347
8348 int32_t tx;
8349 int32_t ret = D_O_K;
8350 int32_t sd=2; //selected delta
8351 static bool skipredraw = false;
8352 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8353 ASSERT(d);
8354
8355 if(d->dp==NULL) return D_O_K;
8356
8357 FONT *oldfont = font;
8358 if(d->dp2)
8359 {
8360 font = (FONT *)d->dp2;
8361 }
8362
8363 switch(msg)
8364 {
8365 case MSG_DRAW:
8366 {
8367 if(skipredraw)
8368 {
8369 skipredraw = false;
8370 ret = D_REDRAW;
8371 break;
8372 }
8373 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8374 {
8375 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8376 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8377 vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8378 vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8379 vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8380 vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8381 hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8382 hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8383 tx=d->x;
8384
8385 if(d->dp)
8386 {
8387 if(panel->getCurrentIndex() != d->d1)
8388 {
8389 hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8390 hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8391 }
8392
8393 tx+=2;
8394
8395 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8396 {
8397 sd=(i==panel->getCurrentIndex())?0:2;
8398
8399 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8400 {
8401 vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8402 vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8403 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8404 }
8405
8406 hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8407 hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8408
8409 if(i!=panel->getCurrentIndex())
8410 {
8411 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8412 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8413 }
8414 else if(d->flags & D_GOTFOCUS)
8415 {
8416 hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8417 hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8418 }
8419
8420 tx+=4;
8421 uint8_t* pname = (uint8_t*)(panel->getName(i));
8422 bool dis = panel->getDisabled(i);
8423 if(dis)
8424 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8425 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8426 tx+=text_length(font, (const char*)pname)+10;
8427
8428 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8429 {
8430 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8431 vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8432 vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8433 }
8434
8435 tx++;
8436 }
8437
8438 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8439 {
8440 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8441 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8442 }
8443 }
8444
8445 if((tx+(2-sd))<(d->x+d->w))
8446 {
8447 hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8448 hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8449 }
8450
8451 }
8452 }
8453 break;
8454
8455 case MSG_WANTFOCUS:
8456 // if(gui_mouse_b())
8457 ret = D_WANTFOCUS|D_REDRAW;
8458 break;
8459 case MSG_GOTFOCUS:
8460 case MSG_LOSTFOCUS:
8461 skipredraw = true;
8462 break;
8463 case MSG_CHAR:
8464 {
8465 int32_t ind = panel->getCurrentIndex();
8466 auto oldind = ind;
8467 switch(c>>8)
8468 {
8469 case KEY_LEFT:
8470 do
8471 {
8472 if(ind > 0)
8473 {
8474 --ind;
8475 }
8476 else
8477 {
8478 ind = panel->getSize()-1;
8479 }
8480 }
8481 while(ind != oldind && panel->getDisabled(ind));
8482 break;
8483 case KEY_RIGHT:
8484 do
8485 {
8486 if(ind+1 < signed(panel->getSize()))
8487 {
8488 ++ind;
8489 }
8490 else
8491 {
8492 ind = 0;
8493 }
8494 }
8495 while(ind != oldind && panel->getDisabled(ind));
8496 break;
8497 default: ind = -1;
8498 }
8499 if(ind > -1 && ind != oldind)
8500 {
8501 panel->switchTo(ind);
8502 GUI_EVENT(d, geCHANGE_SELECTION);
8503 ret |= D_USED_CHAR;
8504 }
8505 }
8506 break;
8507
8508 case MSG_CLICK:
8509 {
8510 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8511 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8512 {
8513 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8514 {
8515 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8516 {
8517 if(d->d1>0)
8518 {
8519 --d->d1;
8520 }
8521
8522 ret |= D_REDRAW;
8523 }
8524 }
8525 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8526 {
8527 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8528 {
8529 size_t t = last_visible_tab(panel, d->d1, d->w);
8530 if(t<(panel->getSize()-1))
8531 {
8532 while(t==last_visible_tab(panel, d->d1, d->w))
8533 ++d->d1;
8534 }
8535
8536 ret |= D_REDRAW;
8537 }
8538 }
8539 }
8540 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8541 {
8542 // find out what the new tab (tb) will be (where the mouse is)
8543 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8544 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8545 {
8546 panel->switchTo(newtab);
8547 GUI_EVENT(d, geCHANGE_SELECTION);
8548 }
8549 }
8550 }
8551 break;
8552 }
8553 font = oldfont;
8554 return ret;
8555 }
8556
8557
8558
8559
8560 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8561 {
8562 ASSERT(d);
8563
8564 if(msg==MSG_DRAW)
8565 {
8566 if(d->w < 1) return D_O_K;
8567 for(int q = 0; q <= d->d1; ++q)
8568 {
8569 if(d->d2&1)
8570 {
8571 hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8572 }
8573 else
8574 {
8575 hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8576 hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8577 }
8578 }
8579 }
8580
8581 return D_O_K;
8582 }
8583
8584 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8585 {
8586 ASSERT(d);
8587
8588 if(msg==MSG_DRAW)
8589 {
8590 if(d->h < 1) return D_O_K;
8591 for(int q = 0; q <= d->d1; ++q)
8592 {
8593 if(d->d2&1)
8594 {
8595 vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8596 }
8597 else
8598 {
8599 vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8600 vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8601 }
8602 }
8603 }
8604
8605 return D_O_K;
8606 }
8607
8608 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8609 {
8610 return d_editbox_proc(msg, d, c);
8611 }
8612
8613 //centers dialog based on first object, which should be the containing window
8614 4180 void jwin_center_dialog(DIALOG *dialog)
8615 {
8616 int32_t xc, yc;
8617 int32_t c;
8618 ASSERT(dialog);
8619
8620 /* how much to move by? */
8621 4180 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8622 4180 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8623
8624 /* move it */
8625
2/2
✓ Branch 0 taken 89694 times.
✓ Branch 1 taken 4180 times.
93874 for(c=0; dialog[c].proc; c++)
8626 {
8627 89694 dialog[c].x += xc;
8628 89694 dialog[c].y += yc;
8629 89694 }
8630 4180 }
8631 //up-left aligns dialog based on first object, which should be the containing window
8632 void jwin_ulalign_dialog(DIALOG *dialog)
8633 {
8634 int32_t xc, yc;
8635 int32_t c;
8636 ASSERT(dialog);
8637
8638 /* how much to move by? */
8639 xc = dialog[0].x;
8640 yc = dialog[0].y;
8641
8642 /* move it */
8643 for(c=0; dialog[c].proc; c++)
8644 {
8645 dialog[c].x -= xc;
8646 dialog[c].y -= yc;
8647 }
8648 }
8649
8650 //Custom slider proc
8651 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8652 {
8653 BITMAP *gui_bmp = screen;
8654 BITMAP *slhan = NULL;
8655 int32_t oldpos, newpos;
8656 int32_t sfg; /* slider foreground color */
8657 int32_t vert = TRUE; /* flag: is slider vertical? */
8658 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8659 int32_t hmar; /* handle margin */
8660 int32_t slp; /* slider position */
8661 int32_t mp; /* mouse position */
8662 int32_t irange;
8663 int32_t slx, sly, slh, slw;
8664 int32_t msx, msy;
8665 int32_t retval = D_O_K;
8666 int32_t upkey, downkey;
8667 int32_t pgupkey, pgdnkey;
8668 int32_t homekey, endkey;
8669 int32_t delta;
8670 fixed slratio, slmax, slpos;
8671 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8672 SLIDER_TYPE proc = NULL;
8673 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8674 int32_t oldval;
8675 ASSERT(d);
8676
8677 /* check for slider direction */
8678 if(d->h < d->w)
8679 vert = FALSE;
8680
8681 /* set up the metrics for the control */
8682 if(d->dp != NULL)
8683 {
8684 slhan = (BITMAP *)d->dp;
8685
8686 if(vert)
8687 hh = slhan->h;
8688 else
8689 hh = slhan->w;
8690 }
8691
8692 hmar = hh/2;
8693 irange = (vert) ? d->h : d->w;
8694 slmax = itofix(irange-hh);
8695 slratio = slmax / (d->d1);
8696 slpos = slratio * d->d2;
8697 slp = fixtoi(slpos);
8698
8699 switch(msg)
8700 {
8701
8702 case MSG_DRAW:
8703 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8704
8705 if(vert)
8706 {
8707 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8708 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8709 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8710 }
8711 else
8712 {
8713 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8714 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8715 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8716 }
8717
8718 /* okay, background and slot are drawn, now draw the handle */
8719 if(slhan)
8720 {
8721 if(vert)
8722 {
8723 slx = d->x+(d->w/2)-(slhan->w/2);
8724 sly = d->y+(d->h-1)-(hh+slp);
8725 }
8726 else
8727 {
8728 slx = d->x+slp;
8729 sly = d->y+(d->h/2)-(slhan->h/2);
8730 }
8731
8732 draw_sprite(gui_bmp, slhan, slx, sly);
8733 }
8734 else
8735 {
8736 /* draw default handle */
8737 if(vert)
8738 {
8739 slx = d->x;
8740 sly = d->y+(d->h)-(hh+slp);
8741 slw = d->w-1;
8742 slh = hh-1;
8743 }
8744 else
8745 {
8746 slx = d->x+slp;
8747 sly = d->y;
8748 slw = hh-1;
8749 slh = d->h-1;
8750 }
8751
8752 /* draw body */
8753 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8754 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8755 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8756 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8757 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8758 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8759 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8760 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8761 }
8762
8763 if(d->flags & D_GOTFOCUS)
8764 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8765
8766 break;
8767
8768 case MSG_WANTFOCUS:
8769 case MSG_LOSTFOCUS:
8770 return D_WANTFOCUS;
8771
8772 case MSG_KEY:
8773 if(!(d->flags & D_GOTFOCUS))
8774 return D_WANTFOCUS;
8775 else
8776 return D_O_K;
8777
8778 case MSG_CHAR:
8779 /* handle movement keys to move slider */
8780 c >>= 8;
8781
8782 if(vert)
8783 {
8784 upkey = KEY_UP;
8785 downkey = KEY_DOWN;
8786 pgupkey = KEY_PGUP;
8787 pgdnkey = KEY_PGDN;
8788 homekey = KEY_END;
8789 endkey = KEY_HOME;
8790 }
8791 else
8792 {
8793 upkey = KEY_RIGHT;
8794 downkey = KEY_LEFT;
8795 pgupkey = KEY_PGDN;
8796 pgdnkey = KEY_PGUP;
8797 homekey = KEY_HOME;
8798 endkey = KEY_END;
8799 }
8800
8801 if(c == upkey)
8802 delta = 1;
8803 else if(c == downkey)
8804 delta = -1;
8805 else if(c == pgdnkey)
8806 delta = -d->d1 / 16;
8807 else if(c == pgupkey)
8808 delta = d->d1 / 16;
8809 else if(c == homekey)
8810 delta = -d->d2;
8811 else if(c == endkey)
8812 delta = d->d1 - d->d2;
8813 else
8814 delta = 0;
8815
8816 if(delta)
8817 {
8818 oldpos = slp;
8819 oldval = d->d2;
8820
8821 //while (true) {
8822 for(; ;) //thank you, MSVC ~pkmnfrk
8823 {
8824 d->d2 = d->d2+delta;
8825 slpos = slratio*d->d2;
8826 slp = fixtoi(slpos);
8827
8828 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8829 break;
8830 }
8831
8832 if(d->d2 < 0)
8833 d->d2 = 0;
8834
8835 if(d->d2 > d->d1)
8836 d->d2 = d->d1;
8837
8838 retval = D_USED_CHAR;
8839
8840 if(d->d2 != oldval)
8841 {
8842 /* call callback function here */
8843 if(d->dp2)
8844 {
8845 proc = (SLIDER_TYPE)(d->dp2);
8846 retval |= (*proc)(d->dp3, d->d2);
8847 }
8848
8849 GUI_EVENT(d, geCHANGE_VALUE);
8850
8851 object_message(d, MSG_DRAW, 0);
8852 }
8853 }
8854
8855 break;
8856
8857 case MSG_WANTWHEEL:
8858 return 1;
8859
8860 case MSG_WHEEL:
8861 oldval = d->d2;
8862 d->d2 = MID(0, d->d2+c, d->d1);
8863
8864 if(d->d2 != oldval)
8865 {
8866 /* call callback function here */
8867 if(d->dp2)
8868 {
8869 proc = (SLIDER_TYPE)(d->dp2);
8870 retval |= (*proc)(d->dp3, d->d2);
8871 }
8872
8873 GUI_EVENT(d, geCHANGE_VALUE);
8874 object_message(d, MSG_DRAW, 0);
8875 retval |= D_REDRAWME;
8876 }
8877
8878 break;
8879
8880 case MSG_CLICK:
8881 /* track the mouse until it is released */
8882 mp = slp;
8883
8884 while(gui_mouse_b())
8885 {
8886 msx = gui_mouse_x();
8887 msy = gui_mouse_y();
8888 oldval = d->d2;
8889
8890 if(vert)
8891 mp = (d->y+d->h-hmar)-msy;
8892 else
8893 mp = msx-(d->x+hmar);
8894
8895 if(mp < 0)
8896 mp = 0;
8897
8898 if(mp > irange-hh)
8899 mp = irange-hh;
8900
8901 slpos = itofix(mp);
8902 slmax = fixdiv(slpos, slratio);
8903 newpos = fixtoi(slmax);
8904
8905 if(newpos != oldval)
8906 {
8907 d->d2 = newpos;
8908
8909 /* call callback function here */
8910 if(d->dp2 != NULL)
8911 {
8912 proc = (SLIDER_TYPE)(d->dp2);
8913 retval |= (*proc)(d->dp3, d->d2);
8914 }
8915
8916 GUI_EVENT(d, geCHANGE_VALUE);
8917 object_message(d, MSG_DRAW, 0);
8918 }
8919
8920 /* let other objects continue to animate */
8921 broadcast_dialog_message(MSG_IDLE, 0);
8922 update_hw_screen();
8923 }
8924
8925 break;
8926 }
8927
8928 return retval;
8929 }
8930
8931 // This is only used by jwin_check_proc and jwin_radio_proc.
8932 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
8933 {
8934 BITMAP *gui_bmp;
8935 int32_t state1, state2;
8936 int32_t black;
8937 int32_t swap;
8938 int32_t g;
8939 ASSERT(d);
8940
8941 gui_bmp = screen;
8942
8943 switch(msg)
8944 {
8945 case MSG_DRAW:
8946 {
8947 if(d->flags & D_SELECTED)
8948 {
8949 g = 1;
8950 state1 = d->bg;
8951 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8952 }
8953 else
8954 {
8955 g = 0;
8956 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8957 state2 = d->bg;
8958 }
8959
8960 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
8961 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
8962 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
8963
8964 if(d->flags & D_SELECTED)
8965 {
8966 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
8967 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
8968 }
8969 else
8970 {
8971 black = makecol(0,0,0);
8972 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
8973 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
8974 }
8975
8976 if((d->flags & D_GOTFOCUS) &&
8977 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
8978 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
8979
8980 break;
8981 }
8982 case MSG_WANTFOCUS:
8983 return D_WANTFOCUS;
8984
8985 case MSG_KEY:
8986 {
8987 /* close dialog? */
8988 if(d->flags & D_EXIT)
8989 {
8990 return D_CLOSE;
8991 }
8992
8993 /* or just toggle */
8994 d->flags ^= D_SELECTED;
8995 GUI_EVENT(d, geTOGGLE);
8996 object_message(d, MSG_DRAW, 0);
8997 break;
8998 }
8999
9000 case MSG_CLICK:
9001 {
9002 /* what state was the button originally in? */
9003 state1 = d->flags & D_SELECTED;
9004
9005 swap = state1;
9006
9007 /* track the mouse until it is released */
9008 while(gui_mouse_b())
9009 {
9010 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9011 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9012
9013 if(swap)
9014 state2 = !state2;
9015
9016 /* redraw? */
9017 bool should_redraw = false;
9018 if(((state1) && (!state2)) || ((state2) && (!state1)))
9019 {
9020 d->flags ^= D_SELECTED;
9021 GUI_EVENT(d, geTOGGLE);
9022 state1 = d->flags & D_SELECTED;
9023 object_message(d, MSG_DRAW, 0);
9024 should_redraw = true;
9025 }
9026
9027 /* let other objects continue to animate */
9028 int r = broadcast_dialog_message(MSG_IDLE, 0);
9029 if (r & D_REDRAWME) should_redraw = true;
9030
9031 if (should_redraw)
9032 {
9033 update_hw_screen();
9034 }
9035 }
9036
9037 if(d->dp3 != NULL)
9038 {
9039 //object_message(d, MSG_DRAW, 0);
9040 typedef int32_t (*funcType)(void);
9041 funcType func=reinterpret_cast<funcType>(d->dp3);
9042
9043 return func();
9044 }
9045
9046 /* should we close the dialog? */
9047 if(d->flags & D_EXIT)
9048 {
9049 return D_CLOSE;
9050 }
9051 break;
9052 }
9053 }
9054
9055 return D_O_K;
9056 }
9057
9058 //Misc bitmap drawing
9059 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9060 {
9061 line(dest, x1, y1, x2, y2, color);
9062 line(dest, x1, y2, x2, y1, color);
9063 }
9064
9065 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9066 {
9067 if(x2 < x1)
9068 zc_swap(x2,x1);
9069 if(y2 < y1)
9070 zc_swap(y2,y1);
9071 int x3 = ((x2-x1)/2)+x1;
9072 int y3 = y2-(x3-x1);
9073 line(dest, x1, y3, x3, y2, c);
9074 line(dest, x3, y2, x2, y1, c);
9075 }
9076
9077 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9078 {
9079 if(!cb_sz)
9080 cb_sz = sz/2;
9081 int ox = -x+offx, oy = -y+offy;
9082 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9083 }
9084
9085 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9086 {
9087 // This use to be what kept 60fps, but now render_timer_wait handles that.
9088 switch(msg)
9089 {
9090 case MSG_IDLE:
9091 {
9092 broadcast_dialog_message(MSG_VSYNC, c);
9093 if(d->dp)
9094 {
9095 int32_t ret = (*(std::function<int32_t()>*)d->dp)();
9096 switch(ret)
9097 {
9098 case ONTICK_EXIT:
9099 if(d->flags&D_NEW_GUI)
9100 close_new_gui_dlg(d);
9101 return D_EXIT;
9102 case ONTICK_CLOSE:
9103 if(d->flags&D_NEW_GUI)
9104 {
9105 //Simulate a GUI_EVENT for the window proc
9106 DIALOG* window = d-1;
9107 while(window->proc != jwin_win_proc) --window;
9108 int32_t ret = new_gui_event(window-1, geCLOSE);
9109 if(ret >= 0)
9110 return ret;
9111 }
9112 return D_EXIT;
9113 case ONTICK_REDRAW:
9114 return D_REDRAW;
9115 }
9116 }
9117 break;
9118 }
9119 }
9120
9121 return D_O_K;
9122 }
9123
9124 //
9125
9126 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9127 {
9128 draw_checkbox(dest,x,y,sz,sz,value);
9129 }
9130 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9131 {
9132 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9133 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9134
9135 if(value)
9136 {
9137 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9138 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9139 }
9140 }
9141 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9142 {
9143 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9144
9145 if(value)
9146 {
9147 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9148 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9149 }
9150 }
9151
9152 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9153 {
9154 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9155 }
9156 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9157 {
9158 bool over=false;
9159
9160 while(gui_mouse_b())
9161 {
9162 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9163 {
9164 if(!over)
9165 {
9166 value=value?0:1;
9167 draw_checkbox(dest,x,y,wid,hei,value!=0);
9168 over=true;
9169 update_hw_screen();
9170 }
9171 }
9172 else
9173 {
9174 if(over)
9175 {
9176 value=value?0:1;
9177 draw_checkbox(dest,x,y,wid,hei,value!=0);
9178 over=false;
9179 update_hw_screen();
9180 }
9181 }
9182 rest(1);
9183 }
9184
9185 return over;
9186 }
9187 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9188 {
9189 bool over=false;
9190
9191 while(gui_mouse_b())
9192 {
9193 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9194 {
9195 if(!over)
9196 {
9197 value=value?0:1;
9198 draw_checkbox(dest,x,y,wid,hei,value!=0);
9199 over=true;
9200 update_hw_screen();
9201 }
9202 }
9203 else
9204 {
9205 if(over)
9206 {
9207 value=value?0:1;
9208 draw_checkbox(dest,x,y,wid,hei,value!=0);
9209 over=false;
9210 update_hw_screen();
9211 }
9212 }
9213 rest(1);
9214 }
9215
9216 return over;
9217 }
9218
9219 //box_out stuff
9220 static int32_t box_x = 0;
9221 static int32_t box_y = 0;
9222 static bool box_active=false;
9223 static int32_t box_store_x = 0;
9224 428 static FONT *box_title_font=font;
9225 428 static FONT *box_message_font=font;
9226 static int32_t box_style=0;
9227 static int32_t box_titlebar_height=0;
9228 static int32_t box_message_height=0;
9229 static uint8_t box_text_scale=1;
9230 static int32_t box_w=304;
9231 static int32_t box_h=176;
9232 static int32_t box_l=8;
9233 static int32_t box_r=312;
9234 static int32_t box_t=32;
9235 static int32_t box_b=208;
9236 static bool box_log=true;
9237 static char box_log_msg[480];
9238 static int32_t box_msg_pos=0;
9239 static int32_t box_store_pos=0;
9240
9241 int32_t onSnapshot2()
9242 {
9243 char buf[20];
9244 int32_t num=0;
9245
9246 do
9247 {
9248 sprintf(buf, "zelda%03d.bmp", ++num);
9249 }
9250 while(num<999 && exists(buf));
9251
9252 PALETTE temppal;
9253 get_palette(temppal);
9254 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9255 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9256 save_bitmap(buf,screen,temppal);
9257 destroy_bitmap(tempbmp);
9258 return D_O_K;
9259 }
9260
9261 void set_default_box_size()
9262 {
9263 int32_t screen_w = screen->w;
9264 int32_t screen_h = screen->h;
9265
9266 box_w=MIN(512, screen_w-16);
9267 box_h=MIN(256, (screen_h-64)&0xFFF0);
9268
9269 box_l=(screen_w-box_w)/2;
9270 box_t=(screen_h-box_h)/2;
9271 box_r=box_l+box_w;
9272 box_b=box_t+box_h;
9273 }
9274 /* resizes the box */
9275 void set_box_size(int32_t w, int32_t h)
9276 {
9277 int32_t screen_w = zq_screen_w;
9278 int32_t screen_h = zq_screen_h;
9279
9280 if(w <= 0) w = 512;
9281 if(h <= 0) h = 256;
9282 box_w=MIN(w, screen_w-16);
9283 box_h=MIN(h, (screen_h-64)&0xFFF0);
9284
9285 box_l=(screen_w-box_w)/2;
9286 box_t=(screen_h-box_h)/2;
9287 box_r=box_l+box_w;
9288 box_b=box_t+box_h;
9289 }
9290
9291 /* starts outputting a progress message */
9292 9 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9293 {
9294
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (is_headless())
9295 9 return;
9296
9297 box_text_scale=scale;
9298 box_style=style;
9299 box_title_font=(title_font!=NULL)?title_font:font;
9300 box_message_font=(message_font!=NULL)?message_font:font;
9301 box_message_height=text_height(box_message_font)*scale;
9302 box_titlebar_height=title?text_height(box_title_font)+2:0;
9303 set_box_size(w,h);
9304 /*
9305 box_w=BOX_W;
9306 box_h=BOX_H;
9307 box_l=BOX_L;
9308 box_r=BOX_R;
9309 box_t=BOX_T;
9310 box_b=BOX_B;
9311 */
9312 box_log=log;
9313 memset(box_log_msg, 0, 480);
9314 box_msg_pos=0;
9315 box_store_pos=0;
9316
9317 if(!box_active)
9318 popup_zqdialog_start();
9319 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9320
9321 if(title!=NULL)
9322 {
9323 zc_swap(font,box_title_font);
9324 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9325 zc_swap(font,box_title_font);
9326 box_titlebar_height=18;
9327 }
9328
9329
9330 box_store_x = box_x = box_y = 0;
9331 box_active = true;
9332 box_t+=box_titlebar_height;
9333 box_h-=box_titlebar_height;
9334 box_log=log;
9335 memset(box_log_msg, 0, 480);
9336 box_msg_pos=0;
9337 box_store_pos=0;
9338 9 }
9339
9340 /* outputs text to the progress message */
9341 30136 void box_out(const char *msg)
9342 {
9343
1/2
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
30136 string remainder = "";
9344
1/2
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
30136 string temp(msg);
9345
9346
1/2
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
30136 if(box_active)
9347 {
9348 //do primitive text wrapping
9349 uint32_t i;
9350 for(i=0; i<temp.size(); i++)
9351 {
9352 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9353
9354 if(length > box_r-box_l-16)
9355 {
9356 i = zc_max(i-1,0);
9357 break;
9358 }
9359 }
9360
9361 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9362 if(box_text_scale == 1)
9363 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9364 else
9365 {
9366 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9367 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9368 clear_bitmap(tempbit);
9369 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9370 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9371 destroy_bitmap(tempbit);
9372 }
9373 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9374 remainder = temp.substr(i,temp.size()-i);
9375 }
9376
9377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30136 times.
30136 if(box_log)
9378 {
9379 30136 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9380 30136 }
9381
9382
1/2
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
30136 box_x += text_length(box_message_font, msg);
9383 30136 box_msg_pos+=(int32_t)strlen(msg);
9384
9385
2/4
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30136 times.
30136 if(remainder != "")
9386 {
9387 bool oldlog = box_log;
9388 box_log = false;
9389 box_eol();
9390 box_out(remainder.c_str());
9391 box_log = oldlog;
9392 }
9393
9394 // For web, always call update_hw_screen because it yields to the main thread,
9395 // which makes long running tasks like loading a quest not block the main thread,
9396 // which would make SFX sound awful on the title screen.
9397
3/6
✓ Branch 0 taken 30136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30136 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30136 times.
30136 if (box_active || is_web())
9398 update_hw_screen();
9399 30136 }
9400
9401 /* calls box_out, and box_eol for newlines */
9402 void box_out_nl(const char *msg)
9403 {
9404 string line;
9405 istringstream reader(msg);
9406 while (getline(reader, line))
9407 {
9408 box_out(line.c_str());
9409 box_eol();
9410 }
9411 }
9412
9413 /* remembers the current x position */
9414 483 void box_save_x()
9415 {
9416
1/2
✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
483 if(box_active)
9417 {
9418 box_store_x=box_x;
9419 }
9420
9421 483 box_store_pos=box_msg_pos;
9422 483 }
9423
9424 /* remembers the current x position */
9425 156 void box_load_x()
9426 {
9427
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9428 {
9429 box_x=box_store_x;
9430 }
9431
9432 156 box_msg_pos=box_store_pos;
9433 156 }
9434
9435 /* outputs text to the progress message */
9436 15789 void box_eol()
9437 {
9438
1/2
✓ Branch 0 taken 15789 times.
✗ Branch 1 not taken.
15789 if(box_active)
9439 {
9440 box_x = 0;
9441 box_y++;
9442
9443 if((box_y+2)*box_message_height >= box_h)
9444 {
9445 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9446 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9447 box_y--;
9448 }
9449 }
9450
9451 15789 box_msg_pos = 0;
9452
9453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15789 times.
15789 if(box_log)
9454 {
9455 15789 al_trace("%s", box_log_msg);
9456 15789 al_trace("\n");
9457 15789 memset(box_log_msg, 0, 480);
9458 15789 }
9459
9460
1/2
✓ Branch 0 taken 15789 times.
✗ Branch 1 not taken.
15789 if (box_active)
9461 update_hw_screen();
9462 15789 }
9463
9464 /* ends output of a progress message */
9465 811 void box_end(bool pause)
9466 {
9467
1/2
✓ Branch 0 taken 811 times.
✗ Branch 1 not taken.
811 if(box_active)
9468 {
9469 if(pause)
9470 {
9471 box_eol();
9472 box_pause();
9473 }
9474
9475 box_active = false;
9476 popup_zqdialog_end();
9477 }
9478 811 }
9479
9480 /* pauses box output */
9481 void box_pause()
9482 {
9483 if(box_active)
9484 {
9485 box_save_x();
9486 box_out("-- press a key --");
9487
9488 while(gui_mouse_b()) rest(1);
9489 while(!(keypressed() || gui_mouse_b())) rest(1);
9490 while(gui_mouse_b()) rest(1);
9491
9492 clear_keybuf();
9493 box_load_x();
9494 }
9495 }
9496